#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from account_lock import confirm_human_action
from account_registry import Account, AccountRegistry, AccountRegistryKind
from runtime_paths import runtime_dir


def _parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="account-lock",
        description="Human-controlled admission locks for Systray AI accounts.",
    )
    parser.add_argument(
        "--base-dir",
        type=Path,
        default=None,
        help=argparse.SUPPRESS,
    )
    parser.add_argument("--json", action="store_true", help="emit machine-readable output")
    subparsers = parser.add_subparsers(dest="action", required=True)

    status = subparsers.add_parser("status", aliases=["list"], help="show account locks")
    status.add_argument("tool", choices=tuple(kind.value for kind in AccountRegistryKind), nargs="?")
    status.add_argument("account", nargs="?")

    for action in ("lock", "unlock"):
        command = subparsers.add_parser(action, help=f"{action} an account")
        command.add_argument("tool", choices=tuple(kind.value for kind in AccountRegistryKind))
        command.add_argument("account")
    return parser


def _registry(base_dir: Path, tool: str) -> AccountRegistry:
    return AccountRegistry(base_dir=base_dir, kind=AccountRegistryKind(tool))


def _resolve_account(registry: AccountRegistry, token: str) -> Account:
    slug = registry.resolve_profile_token(token)
    if slug is None:
        raise KeyError(token)
    for account in registry.list():
        if account.slug == slug:
            return account
    raise KeyError(token)


def _status_rows(base_dir: Path, tool: str | None, token: str | None) -> list[dict[str, object]]:
    kinds = [AccountRegistryKind(tool)] if tool is not None else list(AccountRegistryKind)
    rows: list[dict[str, object]] = []
    for kind in kinds:
        registry = _registry(base_dir, kind.value)
        accounts = registry.list()
        if token is not None:
            account = _resolve_account(registry, token)
            accounts = [account]
        for account in accounts:
            rows.append(
                {
                    "tool": kind.value,
                    "slug": account.slug,
                    "alias": account.alias,
                    "locked": registry.is_locked(account.slug),
                    "default": registry.default_slug() == account.slug,
                }
            )
    return rows


def _print_rows(rows: list[dict[str, object]], *, as_json: bool) -> None:
    if as_json:
        print(json.dumps({"accounts": rows}, separators=(",", ":")))
        return
    if not rows:
        print("No accounts found.")
        return
    for row in rows:
        marker = "LOCKED" if row["locked"] else "unlocked"
        default = " default" if row["default"] else ""
        print(f"{row['tool']}:{row['slug']}\t{marker}{default}\t{row['alias']}")


def run(argv: list[str]) -> int:
    args = _parser().parse_args(argv)
    base_dir = Path(args.base_dir) if args.base_dir is not None else runtime_dir()
    action = "status" if args.action == "list" else args.action
    if action == "status":
        if args.account is not None and args.tool is None:
            raise ValueError("account requires a tool")
        _print_rows(
            _status_rows(base_dir, args.tool, args.account),
            as_json=args.json,
        )
        return 0

    registry = _registry(base_dir, args.tool)
    account = _resolve_account(registry, args.account)
    target_locked = action == "lock"
    if registry.is_locked(account.slug) == target_locked:
        state = "locked" if target_locked else "unlocked"
        payload = {
            "ok": True,
            "changed": False,
            "account": account.tray_key,
            "state": state,
        }
        if args.json:
            print(json.dumps(payload, separators=(",", ":")))
        else:
            print(f"{account.tray_key} is already {state}.")
        return 0

    confirm_human_action(action, account.tool, account.slug)
    changed = registry.set_locked(account.slug, target_locked)
    state = "locked" if target_locked else "unlocked"
    payload = {
        "ok": True,
        "changed": changed,
        "account": account.tray_key,
        "state": state,
    }
    if args.json:
        print(json.dumps(payload, separators=(",", ":")))
    else:
        verb = "is now" if changed else "is already"
        print(f"{account.tray_key} {verb} {state}.")
    return 0


def main(argv: list[str] | None = None) -> int:
    try:
        return run(sys.argv[1:] if argv is None else argv)
    except KeyError as exc:
        print(f"account-lock: unknown account: {exc.args[0]}", file=sys.stderr)
        return 1
    except (RuntimeError, ValueError) as exc:
        print(f"account-lock: {exc}", file=sys.stderr)
        return getattr(exc, "exit_code", 1)
    except OSError as exc:
        print(f"account-lock: {exc}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    raise SystemExit(main())
