"""Workflow: Email-Accounts verwalten (Monitoring-Postfaecher für Rechnungs-Ingest).

Aufruf:
  python email_accounts.py list
  python email_accounts.py get --id 42
  python email_accounts.py create --device "Claude" --email user@example.com [--folders "INBOX,Archiv"]
  python email_accounts.py update --id 42 [--email ...] [--folders ...] [--status active]
  python email_accounts.py delete --id 42 [--confirm --confirm-email "user@example.com"]

DELETE-Flow:
  1. Vorab-Preview via getEmailAccountDetail: bricht ab, wenn das Konto nicht existiert.
  2. Bestätigung Pflicht:
     - Interaktiv (TTY): exakte Email-Adresse tippen (nicht y/yes).
     - Non-interaktiv: --confirm UND --confirm-email "<email>" nötig.
  3. Audit-Zeile auf stderr nach erfolgreichem DELETE.

Hinweis: `create` legt tatsächlich ein Email-Konto mit OAuth/IMAP-Konfiguration an.
Wird im Regelfall über das Webinterface gemacht. Dieser Workflow ist die
programmatic Escape-Hatch; vor dem Live-Einsatz prüfen, welche Felder der API-Call
tatsächlich erwartet (OAuth-Credentials etc.).
"""
from __future__ import annotations

import argparse
import datetime as _dt
import json
import sys
from pathlib import Path
from typing import Any

try:
    sys.stdout.reconfigure(encoding="utf-8")
except (AttributeError, Exception):
    pass

sys.path.insert(0, str(Path(__file__).parent.parent))

from gmi_client import GmiClient, GmiHttpError  # noqa: E402


# ---------- Fetcher ----------

def _unwrap_list(response: Any) -> list[dict]:
    """Email-Accounts-List kann bare Liste ODER Wrapper sein. Defensiv parsen."""
    if isinstance(response, list):
        return response
    if isinstance(response, dict):
        for key in ("emailAccounts", "records", "data", "items"):
            val = response.get(key)
            if isinstance(val, list):
                return val
    return []


def list_email_accounts(client: GmiClient) -> dict:
    try:
        r = client.call("getEmailAccountsList")
    except GmiHttpError as e:
        return {"ok": False, "error": f"http_{e.status}", "detail": str(e)}
    items = _unwrap_list(r)
    return {"ok": True, "count": len(items), "accounts": items}


def get_email_account(client: GmiClient, account_id: int) -> dict:
    try:
        r = client.call("getEmailAccountDetail", emailAccountId=account_id)
    except GmiHttpError as e:
        if e.status == 404:
            return {"ok": False, "error": "not_found", "emailAccountId": account_id}
        return {"ok": False, "error": f"http_{e.status}", "detail": str(e)}
    return {"ok": True, "account": r}


def _get_one_email_account(client: GmiClient, account_id: int) -> dict | None:
    """Preview-Helper. Normalisiert die diversen Response-Formen."""
    try:
        r = client.call("getEmailAccountDetail", emailAccountId=account_id)
    except GmiHttpError as e:
        if e.status == 404:
            return None
        raise
    if isinstance(r, dict):
        return r
    if isinstance(r, list):
        return r[0] if r else None
    return None


# ---------- Write operations ----------

def create_email_account(
    client: GmiClient,
    device_name: str | None,
    email: str | None,
    monitor_folders: list[str] | None,
    extra: dict[str, Any] | None = None,
) -> dict:
    body: dict[str, Any] = {}
    if device_name is not None:
        body["deviceName"] = device_name
    if email is not None:
        body["email"] = email
    if monitor_folders is not None:
        body["monitorFolders"] = monitor_folders
    if extra:
        body.update(extra)
    try:
        resp = client.call("createNewEmailAccount", _body=body)
    except GmiHttpError as e:
        return {"ok": False, "error": f"http_{e.status}", "detail": str(e)}
    return {"ok": True, "action": "create", "response": resp}


def update_email_account(
    client: GmiClient,
    account_id: int,
    email: str | None,
    monitor_folders: list[str] | None,
    status: str | None,
) -> dict:
    body: dict[str, Any] = {}
    if email is not None:
        body["email"] = email
    if monitor_folders is not None:
        body["monitorFolders"] = monitor_folders
    if status is not None:
        body["status"] = status
    if not body:
        return {"ok": False, "error": "empty_update",
                "hint": "Mindestens eines von --email, --folders, --status setzen"}
    try:
        resp = client.call(
            "updateEmailAccount",
            emailAccountId=account_id,
            _body=body,
        )
    except GmiHttpError as e:
        return {"ok": False, "error": f"http_{e.status}", "detail": str(e)}
    return {"ok": True, "action": "update", "emailAccountId": account_id, "response": resp}


def delete_email_account(
    client: GmiClient,
    account_id: int,
    confirm_email: str | None,
    interactive: bool,
) -> dict:
    # Layer 1: Preview-Pflicht
    preview = _get_one_email_account(client, account_id)
    if preview is None:
        return {"ok": False, "error": "not_found", "emailAccountId": account_id}

    actual_email = preview.get("email") or ""

    # Layer 2: Bestätigung Pflicht
    if interactive:
        prompt = (f"\nZu löschen: emailAccountId={account_id}  email={actual_email!r}\n"
                  f"Zur Bestätigung bitte die EXAKTE Email-Adresse eintippen: ")
        try:
            typed = input(prompt)
        except EOFError:
            return {"ok": False, "error": "not_confirmed", "reason": "no_tty_input"}
        if typed.strip() != actual_email:
            return {"ok": False, "error": "email_mismatch", "expected": actual_email,
                    "emailAccountId": account_id}
    else:
        if not confirm_email:
            return {"ok": False, "error": "missing_confirm_email",
                    "hint": "Non-interaktiv --confirm UND --confirm-email '<email>' setzen",
                    "emailAccountId": account_id, "expected": actual_email}
        if confirm_email != actual_email:
            return {"ok": False, "error": "email_mismatch", "expected": actual_email,
                    "got": confirm_email, "emailAccountId": account_id}

    try:
        resp = client.call("deleteEmailAccount", emailAccountId=account_id)
    except GmiHttpError as e:
        return {"ok": False, "error": f"http_{e.status}", "detail": str(e),
                "emailAccountId": account_id}

    ts = _dt.datetime.now().isoformat(timespec="seconds")
    print(f"[DELETE] emailAccounts/{account_id} \"{actual_email}\" at {ts}", file=sys.stderr)

    return {"ok": True, "action": "delete", "emailAccountId": account_id,
            "email": actual_email, "response": resp}


# ---------- Formatting ----------

def format_list_md(data: dict) -> str:
    items = data.get("accounts", [])
    header = f"## Email-Accounts ({data.get('count', 0)})"
    if not items:
        return header + "\n\n(keine)"
    lines = [header, "",
             "| emailAccountId | Email | Device | Status | Folders |",
             "|---|---|---|---|---|"]
    for a in items:
        folders = a.get("monitorFolders") or []
        lines.append("| {id} | {email} | {dev} | {status} | {folders} |".format(
            id=a.get("emailAccountId") or a.get("id") or "",
            email=a.get("email") or "",
            dev=a.get("deviceName") or "",
            status=a.get("status") or "",
            folders=",".join(folders) if isinstance(folders, list) else str(folders),
        ))
    return "\n".join(lines)


def format_detail_md(data: dict) -> str:
    acc = data.get("account") or {}
    if not acc:
        return "## Email-Account\n\n(leer)"
    if isinstance(acc, list):
        acc = acc[0] if acc else {}
    lines = [f"## Email-Account {acc.get('emailAccountId') or acc.get('id', '?')}", ""]
    for k in ("email", "deviceName", "status", "monitorFolders", "lastChecked"):
        if k in acc and acc[k] not in (None, "", []):
            lines.append(f"- **{k}:** {acc[k]}")
    return "\n".join(lines)


def format_write_md(data: dict) -> str:
    action = data.get("action", "?")
    lines = [f"## {action} — OK", ""]
    if data.get("emailAccountId"):
        lines.append(f"- **emailAccountId:** {data['emailAccountId']}")
    if data.get("email"):
        lines.append(f"- **email:** {data['email']}")
    if data.get("response"):
        lines.append("")
        lines.append("```json")
        lines.append(json.dumps(data["response"], indent=2, ensure_ascii=False))
        lines.append("```")
    return "\n".join(lines)


def format_error_md(data: dict) -> str:
    return f"## Fehler\n\n```json\n{json.dumps(data, indent=2, ensure_ascii=False, default=str)}\n```"


# ---------- CLI ----------

def _print(data: dict, args: argparse.Namespace) -> None:
    if args.format == "json":
        print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
        return
    if not data.get("ok"):
        print(format_error_md(data))
        return
    if "accounts" in data:
        print(format_list_md(data))
    elif "account" in data:
        print(format_detail_md(data))
    else:
        print(format_write_md(data))


def _parse_folders(raw: str | None) -> list[str] | None:
    if raw is None:
        return None
    return [f.strip() for f in raw.split(",") if f.strip()]


def main() -> int:
    common = argparse.ArgumentParser(add_help=False)
    common.add_argument("--format", choices=["json", "markdown"], default="markdown")

    p = argparse.ArgumentParser(parents=[common])
    sub = p.add_subparsers(dest="cmd", required=True)

    sub.add_parser("list", parents=[common], help="Email-Accounts listen")

    gp = sub.add_parser("get", parents=[common], help="Detail eines Email-Accounts")
    gp.add_argument("--id", type=int, required=True, dest="account_id",
                    help="emailAccountId")

    cp = sub.add_parser("create", parents=[common], help="Neuen Email-Account anlegen")
    cp.add_argument("--device", dest="device_name")
    cp.add_argument("--email")
    cp.add_argument("--folders", dest="monitor_folders",
                    help="Kommagetrennte Folder-Liste, z.B. 'INBOX,Archiv'")

    up = sub.add_parser("update", parents=[common], help="Email-Account aktualisieren (PATCH)")
    up.add_argument("--id", type=int, required=True, dest="account_id")
    up.add_argument("--email")
    up.add_argument("--folders", dest="monitor_folders")
    up.add_argument("--status")

    dp = sub.add_parser("delete", parents=[common], help="Email-Account löschen (Confirm-Pflicht)")
    dp.add_argument("--id", type=int, required=True, dest="account_id")
    dp.add_argument("--confirm", action="store_true",
                    help="Non-interaktiv: zusammen mit --confirm-email setzen")
    dp.add_argument("--confirm-email", dest="confirm_email",
                    help="Exakte Email, muss matchen")

    args = p.parse_args()

    try:
        client = GmiClient()
    except Exception as e:
        print(json.dumps({"error": "config", "detail": str(e)}))
        return 1

    try:
        if args.cmd == "list":
            data = list_email_accounts(client)
        elif args.cmd == "get":
            data = get_email_account(client, args.account_id)
        elif args.cmd == "create":
            data = create_email_account(
                client, args.device_name, args.email,
                _parse_folders(args.monitor_folders),
            )
        elif args.cmd == "update":
            data = update_email_account(
                client, args.account_id, args.email,
                _parse_folders(args.monitor_folders), args.status,
            )
        elif args.cmd == "delete":
            interactive = sys.stdin.isatty() and not args.confirm
            data = delete_email_account(
                client, args.account_id,
                confirm_email=args.confirm_email,
                interactive=interactive,
            )
        else:
            print(json.dumps({"error": "unknown_command", "cmd": args.cmd}))
            return 1
    except GmiHttpError as e:
        print(json.dumps({"error": "api", "status": e.status, "detail": str(e)}))
        return 1

    _print(data, args)
    return 0 if data.get("ok") else 1


if __name__ == "__main__":
    sys.exit(main())
