"""Email account payload parsing and normalization for preferences + IMAP test route."""
from __future__ import annotations

_EMAIL_SCHEMA_VERSION = 2
_EMAIL_MAX_ACCOUNTS = 25
_EMAIL_ALLOWED_TOP_LEVEL_KEYS = frozenset({"schema_version", "accounts", "default_account_id"})
_EMAIL_ALLOWED_ACCOUNT_KEYS = frozenset(
    {"id", "label", "imap_host", "imap_port", "imap_user", "enabled", "provider_hint", "password"}
)


def _email_err(message: str, code: int = 400) -> tuple[None, None, str, int]:
    return None, None, message, code


def _sanitize_email_string(raw: object, *, max_len: int) -> str:
    return str(raw or "").strip()[:max_len]


def prepare_email_config_for_response(config: dict) -> tuple[dict, bool]:
    from core.config import normalize_email_config

    normalized, changed = normalize_email_config(config.get("email") if isinstance(config, dict) else {})
    return normalized, bool(changed)


def parse_email_config_payload(raw: object) -> tuple[dict | None, dict | None, str | None, int]:
    if not isinstance(raw, dict):
        return _email_err("Email settings payload must be an object.")
    unknown_top = set(raw.keys()) - set(_EMAIL_ALLOWED_TOP_LEVEL_KEYS)
    if unknown_top:
        return _email_err(f"Unknown email settings fields: {', '.join(sorted(unknown_top))}")

    accounts_raw = raw.get("accounts")
    if not isinstance(accounts_raw, list):
        return _email_err("email.accounts must be a list.")
    if len(accounts_raw) > _EMAIL_MAX_ACCOUNTS:
        return _email_err(f"Too many email accounts (max {_EMAIL_MAX_ACCOUNTS}).")

    default_account_id = _sanitize_email_string(raw.get("default_account_id"), max_len=120)
    accounts: list[dict] = []
    password_updates: dict[str, str] = {}
    seen_ids: set[str] = set()
    seen_pairs: set[tuple[str, str]] = set()

    for idx, item in enumerate(accounts_raw):
        if not isinstance(item, dict):
            return _email_err(f"Account at index {idx} must be an object.")
        unknown_keys = set(item.keys()) - set(_EMAIL_ALLOWED_ACCOUNT_KEYS)
        if unknown_keys:
            return _email_err(
                f"Account {idx} has unknown fields: {', '.join(sorted(unknown_keys))}"
            )
        account_id = _sanitize_email_string(item.get("id"), max_len=120)
        if not account_id:
            return _email_err(f"Account {idx} is missing id.")
        if account_id in seen_ids:
            return _email_err(f"Duplicate account id: {account_id}")
        seen_ids.add(account_id)

        label = _sanitize_email_string(item.get("label"), max_len=120)
        host = _sanitize_email_string(item.get("imap_host"), max_len=255)
        user = _sanitize_email_string(item.get("imap_user"), max_len=255)
        provider_hint = _sanitize_email_string(item.get("provider_hint"), max_len=60)
        enabled = bool(item.get("enabled", True))
        port_val = item.get("imap_port")
        try:
            port = int(port_val) if port_val is not None else 993
        except Exception:
            return _email_err(f"Invalid imap_port for account {account_id}.")
        if port < 1 or port > 65535:
            return _email_err(f"Invalid imap_port for account {account_id}.")
        if not host:
            return _email_err(f"imap_host is required for account {account_id}.")
        if not user:
            return _email_err(f"imap_user is required for account {account_id}.")
        if not label:
            label = user

        host_user = (host.lower(), user.lower())
        if host_user in seen_pairs:
            return _email_err(f"Duplicate account for {user}@{host}.")
        seen_pairs.add(host_user)

        if "password" in item:
            password_updates[account_id] = _sanitize_email_string(item.get("password"), max_len=4096)

        accounts.append(
            {
                "id": account_id,
                "label": label,
                "imap_host": host,
                "imap_port": port,
                "imap_user": user,
                "enabled": enabled,
                "provider_hint": provider_hint,
            }
        )

    if default_account_id and not any(a["id"] == default_account_id for a in accounts):
        return _email_err("default_account_id must match one of email.accounts.")
    if accounts and not default_account_id:
        enabled_accounts = [a for a in accounts if a.get("enabled", True)]
        default_account_id = enabled_accounts[0]["id"] if enabled_accounts else accounts[0]["id"]
    if not accounts:
        default_account_id = ""

    normalized = {
        "schema_version": _EMAIL_SCHEMA_VERSION,
        "accounts": accounts,
        "default_account_id": default_account_id,
    }
    return normalized, password_updates, None, 200


def select_email_account_for_test(
    email_cfg: dict,
    account_id: str,
    body: dict,
) -> dict:
    accounts = list((email_cfg or {}).get("accounts") or [])
    default_id = str((email_cfg or {}).get("default_account_id") or "").strip()
    selected = None
    if account_id:
        selected = next((a for a in accounts if str(a.get("id") or "") == account_id), None)
    if selected is None and default_id:
        selected = next((a for a in accounts if str(a.get("id") or "") == default_id), None)
    if selected is None and accounts:
        selected = next((a for a in accounts if bool(a.get("enabled", True))), accounts[0])
    selected = selected or {}
    return {
        "id": str(selected.get("id") or ""),
        "imap_host": (body.get("imap_host") or selected.get("imap_host") or "").strip(),
        "imap_port": body.get("imap_port") if body.get("imap_port") is not None else selected.get("imap_port"),
        "imap_user": (body.get("imap_user") or selected.get("imap_user") or "").strip(),
    }
