"""Workflow: Stammdaten-Lesetoolkit (Account, Companies, Countries, Currencies, VAT, Tags, BankAccounts).

Aufruf:
  python lookup_masterdata.py --kind account
  python lookup_masterdata.py --kind companies --filter Amazon
  python lookup_masterdata.py --kind countries --filter DE --format json
  python lookup_masterdata.py --kind all

Read-Only. Bricht bei Banking sauber ab, wenn das Account-Paket keinen Banking-Zugriff hat.
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Any

# Windows cp1252-stdout kann einige Unicode-Zeichen aus Laender-/Firmennamen
# (z.B. polnisches "l-mit-strich") nicht darstellen. Safe auf utf-8 umstellen.
try:
    sys.stdout.reconfigure(encoding="utf-8")  # Python 3.7+
except (AttributeError, Exception):
    pass

# Parent-Ordner zum Pfad für gmi_client Import
sys.path.insert(0, str(Path(__file__).parent.parent))

from gmi_client import GmiClient, GmiHttpError  # noqa: E402


KINDS = ["account", "companies", "countries", "currencies", "vatrates", "tags", "bankaccounts", "all"]


# ---------- Fetchers ----------

def fetch_account(client: GmiClient) -> dict:
    """getAccountDetails -> Dict (30+ Felder)."""
    return client.call("getAccountDetails") or {}


def fetch_companies(client: GmiClient) -> list[dict]:
    """getCompanyList -> Liste von Company-Dicts."""
    r = client.call("getCompanyList")
    return r if isinstance(r, list) else []


def fetch_countries(client: GmiClient) -> list[dict]:
    """getCountryList -> Liste von 240 Laendern."""
    r = client.call("getCountryList")
    return r if isinstance(r, list) else []


def fetch_currencies(client: GmiClient) -> list[dict]:
    """getCurrencyList -> Liste (name, currencyCode)."""
    r = client.call("getCurrencyList")
    return r if isinstance(r, list) else []


def fetch_vatrates(client: GmiClient) -> list[Any]:
    """getVatRates -> Wrapper {success, data}. Entpackt die Liste."""
    r = client.call("getVatRates")
    if isinstance(r, dict) and "data" in r:
        data = r.get("data")
        return data if isinstance(data, list) else []
    return r if isinstance(r, list) else []


def fetch_tags(client: GmiClient) -> list[dict]:
    """getTagList -> Liste von Tag-Dicts (ggf. leer)."""
    r = client.call("getTagList")
    return r if isinstance(r, list) else []


def fetch_bankaccounts(client: GmiClient, account: dict | None = None) -> dict:
    """listBankAccounts mit Permission-Gate.

    Liefert:
      {"locked": True, "reason": "hasBankingAccess=false"} — wenn Account kein Banking hat
      {"locked": False, "items": [...]}                    — sonst
      {"locked": True, "reason": "http_403"}                — bei API-403 trotz Flag
    """
    acc = account if account is not None else fetch_account(client)
    if not acc.get("hasBankingAccess"):
        return {"locked": True, "reason": "hasBankingAccess=false", "items": []}
    try:
        r = client.call("listBankAccounts")
    except GmiHttpError as e:
        status = getattr(e, "status", None)
        if status == 403:
            return {"locked": True, "reason": "http_403", "items": []}
        raise
    items = r if isinstance(r, list) else (r.get("data") if isinstance(r, dict) else [])
    return {"locked": False, "items": items or []}


# ---------- Filtering ----------

def _match(item: dict, needle: str, fields: tuple[str, ...]) -> bool:
    n = needle.lower()
    for f in fields:
        v = item.get(f)
        if v is None:
            continue
        if n in str(v).lower():
            return True
    return False


def filter_items(kind: str, items: list, needle: str | None) -> list:
    if not needle:
        return items
    if kind == "companies":
        return [c for c in items if _match(c, needle, ("name", "creditorNumber", "companyType"))]
    if kind == "countries":
        return [c for c in items if _match(c, needle, ("name", "countryCode"))]
    if kind == "currencies":
        return [c for c in items if _match(c, needle, ("name", "currencyCode"))]
    if kind == "tags":
        return [t for t in items if _match(t, needle, ("name", "tag", "label"))]
    return items


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

def _fmt_account_md(acc: dict) -> str:
    lines = ["## Account", ""]
    lines.append(f"- Name: {acc.get('name','')}")
    lines.append(f"- Organisation: {acc.get('organization','')}")
    lines.append(f"- E-Mail: {acc.get('email','')}")
    lines.append(f"- accountUid: {acc.get('accountUid','')}")
    lines.append(f"- Land: {acc.get('country','')}")
    lines.append(f"- Währung: {acc.get('currency','')}")
    lines.append(f"- Zeitzone: {acc.get('timezone','')}")
    lines.append(f"- Datumsformat: {acc.get('dateFormat','')}")
    lines.append(f"- Import-Mail: {acc.get('importMailAddress','')}")
    lines.append(f"- Paket: {acc.get('package','') or '-'}")
    lines.append(f"- API-Key-Typ: {acc.get('apiKeyType','')}")
    lines.append(f"- Banking-Zugriff: {'ja' if acc.get('hasBankingAccess') else 'nein'}")
    lines.append(f"- Workflow-Zugriff: {'ja' if acc.get('hasWorkflowAccess') else 'nein'}")
    vr = acc.get("vat_rates") or []
    lines.append(f"- MwSt-Saetze (Account): {', '.join(str(v) for v in vr) if vr else '-'}")
    return "\n".join(lines)


def _fmt_companies_md(items: list[dict]) -> str:
    lines = [f"## Companies ({len(items)})", "",
             "| companyUid | Name | Typ | Land | Kreditor |",
             "|---|---|---|---|---|"]
    for c in items:
        lines.append("| {uid} | {name} | {typ} | {cc} | {kred} |".format(
            uid=c.get("companyUid", ""),
            name=c.get("name", ""),
            typ=c.get("companyType", ""),
            cc=c.get("countryCode") or "",
            kred=c.get("creditorNumber") or "",
        ))
    return "\n".join(lines)


def _fmt_countries_md(items: list[dict]) -> str:
    lines = [f"## Countries ({len(items)})", "",
             "| countryUid | Code | Name | EU | VAT |",
             "|---|---|---|---|---|"]
    for c in items:
        lines.append("| {uid} | {code} | {name} | {eu} | {vat} |".format(
            uid=c.get("countryUid", ""),
            code=c.get("countryCode", ""),
            name=c.get("name", ""),
            eu="ja" if str(c.get("is_eu", "0")) == "1" else "nein",
            vat=c.get("vat", ""),
        ))
    return "\n".join(lines)


def _fmt_currencies_md(items: list[dict]) -> str:
    lines = [f"## Currencies ({len(items)})", "",
             "| Code | Name |",
             "|---|---|"]
    for c in items:
        lines.append(f"| {c.get('currencyCode','')} | {c.get('name','')} |")
    return "\n".join(lines)


def _fmt_vatrates_md(items: list) -> str:
    if not items:
        return "## MwSt-Saetze\n\n(keine)"
    return "## MwSt-Saetze\n\n" + ", ".join(f"{v}%" for v in items)


def _fmt_tags_md(items: list[dict]) -> str:
    if not items:
        return "## Tags\n\n(keine)"
    lines = [f"## Tags ({len(items)})", ""]
    for t in items:
        label = t.get("name") or t.get("tag") or t.get("label") or str(t)
        lines.append(f"- {label}")
    return "\n".join(lines)


def _fmt_bank_md(bank: dict) -> str:
    if bank.get("locked"):
        reason = bank.get("reason", "")
        return (f"## Bankkonten\n\n"
                f"Gesperrt ({reason}). Banking-Modul ist für diesen Account nicht aktiv.")
    items = bank.get("items", [])
    lines = [f"## Bankkonten ({len(items)})", "",
             "| bankAccountUid | Name | Bank | IBAN | Saldo |",
             "|---|---|---|---|---|"]
    for b in items:
        lines.append("| {uid} | {name} | {bank} | {iban} | {bal} |".format(
            uid=b.get("bankAccountUid") or b.get("uid") or "",
            name=b.get("name") or b.get("accountName") or "",
            bank=b.get("bankName") or b.get("bank") or "",
            iban=b.get("iban") or "",
            bal=b.get("balance") or "",
        ))
    return "\n".join(lines)


# ---------- Orchestration ----------

def collect(client: GmiClient, kind: str, needle: str | None) -> dict:
    """Führt die nötigen API-Calls aus und gibt ein normalisiertes Dict zurück."""
    out: dict[str, Any] = {"kind": kind}

    if kind in ("account", "all"):
        out["account"] = fetch_account(client)
    if kind in ("companies", "all"):
        items = fetch_companies(client)
        out["companies"] = filter_items("companies", items, needle)
    if kind in ("countries", "all"):
        items = fetch_countries(client)
        out["countries"] = filter_items("countries", items, needle)
    if kind in ("currencies", "all"):
        items = fetch_currencies(client)
        out["currencies"] = filter_items("currencies", items, needle)
    if kind in ("vatrates", "all"):
        out["vatrates"] = fetch_vatrates(client)
    if kind in ("tags", "all"):
        items = fetch_tags(client)
        out["tags"] = filter_items("tags", items, needle)
    if kind in ("bankaccounts", "all"):
        acc = out.get("account") if kind == "all" else None
        out["bankaccounts"] = fetch_bankaccounts(client, account=acc)

    return out


def render_markdown(data: dict) -> str:
    parts: list[str] = []
    if "account" in data:
        parts.append(_fmt_account_md(data["account"]))
    if "companies" in data:
        parts.append(_fmt_companies_md(data["companies"]))
    if "countries" in data:
        parts.append(_fmt_countries_md(data["countries"]))
    if "currencies" in data:
        parts.append(_fmt_currencies_md(data["currencies"]))
    if "vatrates" in data:
        parts.append(_fmt_vatrates_md(data["vatrates"]))
    if "tags" in data:
        parts.append(_fmt_tags_md(data["tags"]))
    if "bankaccounts" in data:
        parts.append(_fmt_bank_md(data["bankaccounts"]))
    return "\n\n".join(parts)


def main() -> int:
    p = argparse.ArgumentParser()
    p.add_argument("--kind", choices=KINDS, required=True)
    p.add_argument("--filter", dest="needle", help="Substring-Filter (companies/countries/currencies/tags)")
    p.add_argument("--format", choices=["json", "markdown"], default="markdown")
    args = p.parse_args()

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

    try:
        data = collect(client, args.kind, args.needle)
    except GmiHttpError as e:
        print(json.dumps({"error": "api", "detail": str(e)}))
        return 1

    if args.format == "json":
        print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
    else:
        print(render_markdown(data))
    return 0


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