import importlib
import json
import os
import sys
from typing import Any, Optional


class PartnerCustomerLookupError(RuntimeError):
    pass


try:
    from common.customer_ownership import (
        AK_SK_ERROR_MESSAGE,
        MISSING_IDENTITY_MESSAGE,
        PARTNER_RECHECK_MESSAGE as NON_PARTNER_MESSAGE,
        READY_MESSAGE,
        SERVER_ERROR_MESSAGE,
        WELCOME_MESSAGE,
        classify_auth_exception,
        remote_customer_verify,
    )
except Exception:  # pragma: no cover - backend standalone fallback
    AK_SK_ERROR_MESSAGE = "AK/SK错误，请检查后重试。"
    MISSING_IDENTITY_MESSAGE = "AK/SK已通过，但未能读取可核对的账号归属信息，请联系客户经理确认绑定状态。"
    NON_PARTNER_MESSAGE = "校验AK/SK非合作伙伴，请在软件右上方注册链接内注册/绑定为合作伙伴后继续使用或联系客户经理（软件左侧相同）。"
    WELCOME_MESSAGE = "您好合作伙伴，欢迎使用！查询账号资源中。"
    READY_MESSAGE = WELCOME_MESSAGE
    SERVER_ERROR_MESSAGE = "服务器客户归属校验失败，请稍后重试。"

    def classify_auth_exception(_exc: BaseException) -> str:
        return SERVER_ERROR_MESSAGE

    def remote_customer_verify(_provider: str, **_fields: Any) -> dict[str, Any]:
        raise PartnerCustomerLookupError(SERVER_ERROR_MESSAGE)


BASE_DIR = os.path.dirname(os.path.abspath(__file__))


def _load_api_module(name: str):
    if BASE_DIR not in sys.path:
        sys.path.insert(0, BASE_DIR)
    return importlib.import_module(name)


def _compact(value: Any) -> str:
    return str(value or "").strip().lower()


def _field_token(value: Any) -> str:
    return str(value or "").replace("_", "").replace("-", "").strip().lower()


IDENTITY_KEY_FIELDS = {
    _field_token(field)
    for field in (
        "account_id",
        "account",
        "accountId",
        "accountName",
        "domain_id",
        "domainId",
        "domain_name",
        "domainName",
        "customer_id",
        "customerId",
        "customer_name",
        "customerName",
        "id",
        "name",
    )
}
IDENTITY_KEY_PARTS = ("accountid", "accountname", "domainid", "domainname", "customerid", "customername")
CUSTOMER_MATCH_FIELDS = IDENTITY_KEY_FIELDS | {
    _field_token(field)
    for field in (
        "phone",
        "mobile",
        "mobile_phone",
        "phone_number",
        "email",
        "login_name",
        "user_name",
        "username",
        "display_name",
        "real_name",
    )
}
CUSTOMER_MATCH_PARTS = IDENTITY_KEY_PARTS + ("phonenumber", "mobilephone", "loginname", "username")


def _append_unique(values: list[str], value: Any) -> None:
    item = _compact(value)
    if item and item not in values:
        values.append(item)


def _matching_scalar_values(payload: Any, field_names: set[str], field_parts: tuple[str, ...] = ()) -> list[str]:
    values: list[str] = []

    def visit(value: Any, key: str = "") -> None:
        if isinstance(value, dict):
            for child_key, child_value in value.items():
                visit(child_value, str(child_key))
            return
        if isinstance(value, (list, tuple, set)):
            for child_value in value:
                visit(child_value, key)
            return
        token = _field_token(key)
        if not token:
            return
        if token in field_names or any(part in token for part in field_parts):
            _append_unique(values, value)

    visit(payload)
    return values


def _search_keywords(keys: list[str]) -> list[str]:
    keywords: list[str] = []
    for key in keys:
        _append_unique(keywords, key)
        if len(key) >= 16:
            _append_unique(keywords, key[-8:])
    return keywords


def _customer_items(result: Any) -> list[dict[str, Any]]:
    items: list[dict[str, Any]] = []

    def visit(value: Any, depth: int = 0) -> None:
        if depth > 4:
            return
        if isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    items.append(item)
            return
        if not isinstance(value, dict):
            return
        for field in ("items", "customers", "list", "records", "rows", "data", "result"):
            child = value.get(field)
            if isinstance(child, list):
                visit(child, depth + 1)
            elif isinstance(child, dict):
                visit(child, depth + 1)

    visit(result)
    return items


def _search_customers(service: Any, keyword: str, limit: int) -> dict[str, Any]:
    try:
        return service.search_customers(keyword=keyword, limit=limit)
    except TypeError:
        return service.search_customers(keyword=keyword)


def _ensure_partner_backend_ready(service: Any) -> None:
    sync_metrics = getattr(service, "sync_metrics", None)
    if not callable(sync_metrics):
        return
    try:
        result = sync_metrics()
        if isinstance(result, dict) and result.get("ok") is False:
            raise RuntimeError(result.get("message") or "数据接口返回失败")
    except Exception as exc:
        raise PartnerCustomerLookupError(f"华为云代理后台登录态或数据接口不可用: {exc}") from exc


def _identity_keys(identity: dict[str, Any]) -> list[str]:
    keys: list[str] = []
    for value in _matching_scalar_values(identity, IDENTITY_KEY_FIELDS, IDENTITY_KEY_PARTS):
        _append_unique(keys, value)
    return keys


def _customer_matches(customer: dict[str, Any], keys: list[str]) -> bool:
    direct_values = set(_matching_scalar_values(customer, CUSTOMER_MATCH_FIELDS, CUSTOMER_MATCH_PARTS))
    for key in keys:
        if key in direct_values:
            return True
    haystack = json.dumps(customer, ensure_ascii=False).lower()
    return any(len(key) >= 4 and key in haystack for key in keys)


def _find_customer(keys: list[str]) -> Optional[dict[str, Any]]:
    last_error: Optional[Exception] = None
    try:
        huawei_agent_service = _load_api_module("huawei_agent_service")
        _ensure_partner_backend_ready(huawei_agent_service)
    except PartnerCustomerLookupError:
        raise
    except Exception as exc:
        raise PartnerCustomerLookupError(f"华为云代理后台客户查询失败: {exc}") from exc
    for key in _search_keywords(keys):
        try:
            result = _search_customers(huawei_agent_service, key, 50)
        except Exception as exc:
            last_error = exc
            continue
        if not result.get("ok"):
            continue
        for item in _customer_items(result):
            if isinstance(item, dict) and _customer_matches(item, keys):
                return item
    try:
        result = _search_customers(huawei_agent_service, "", 500)
    except Exception as exc:
        last_error = exc
    else:
        if result.get("ok"):
            for item in _customer_items(result):
                if isinstance(item, dict) and _customer_matches(item, keys):
                    return item
    if last_error is not None:
        raise PartnerCustomerLookupError(f"华为云代理后台客户查询失败: {last_error}")
    return None


def _remote_customer_verify_for_identity(identity: dict[str, Any], mark: str = "") -> dict[str, Any]:
    account_id = str(identity.get("account_id") or "").strip()
    account = str(identity.get("account") or "").strip()
    fields: dict[str, Any] = {
        "account_id": account_id,
        "domain_id": account_id,
        "login_name": account,
        "account_name": account,
        "domain_name": account,
    }
    for domain in identity.get("domains") or []:
        if not isinstance(domain, dict):
            continue
        domain_id = str(domain.get("account_id") or domain.get("id") or "").strip()
        domain_name = str(domain.get("account") or domain.get("name") or "").strip()
        if domain_id and not fields.get("domain_id"):
            fields["domain_id"] = domain_id
        if domain_name and not fields.get("domain_name"):
            fields["domain_name"] = domain_name
    return remote_customer_verify("huawei", **fields)


def validate_customer_ownership(
    ak: str,
    sk: str,
    mark: str = "",
    *,
    skip_partner_check: bool = False,
) -> tuple[bool, str, dict[str, Any]]:
    iam_service = _load_api_module("iam_service")
    try:
        identity = iam_service.get_account_identity_for_credentials(ak, sk)
    except Exception as exc:
        return False, classify_auth_exception(exc), {"error_type": type(exc).__name__}
    if identity.get("enabled") is False:
        return False, AK_SK_ERROR_MESSAGE, {"identity": identity}
    if skip_partner_check:
        return True, "AK/SK校验通过，账号资源读取中。", {
            "identity": identity,
            "partner_check_skipped": True,
        }
    try:
        result = _remote_customer_verify_for_identity(identity, mark)
    except Exception as exc:
        text = str(exc or "")
        if MISSING_IDENTITY_MESSAGE in text:
            return False, MISSING_IDENTITY_MESSAGE, {"identity": identity, "error_type": type(exc).__name__}
        return False, classify_auth_exception(exc), {"identity": identity, "error_type": type(exc).__name__}
    if not result.get("is_customer"):
        return False, NON_PARTNER_MESSAGE, {"identity": identity, "verify": result}
    return True, WELCOME_MESSAGE, {"identity": identity, "verify": result}
