"""云厂商同步服务

将适配器返回的标准化资产（NormalizedVPS / NormalizedDomain / AccountInfo）
写入或更新到资产库。以 (provider_id, external_id) 作为去重键，
已存在则更新状态/详情，不存在则新建资产。
"""

import json
from datetime import datetime
from typing import Optional

from fastapi import HTTPException, status
from sqlmodel import Session, select

from app.adapters import registry
from app.adapters.base import BaseAdapter
from app.core import crypto
from app.models.asset import (
    Asset,
    AssetStatus,
    AssetType,
    DomainDetail,
    VPSDetail,
)
from app.models.provider import Provider

_VALID_STATUS = {s.value for s in AssetStatus}


def _load_config(provider: Provider) -> dict:
    """解密平台的 API 配置 JSON"""
    plain = crypto.decrypt(provider.api_config_encrypted)
    if not plain:
        return {}
    try:
        return json.loads(plain)
    except (json.JSONDecodeError, TypeError):
        return {}


def _get_provider(session: Session, provider_id: int) -> Provider:
    provider = session.get(Provider, provider_id)
    if not provider:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="平台不存在")
    return provider


def _build_adapter(provider: Provider) -> BaseAdapter:
    if not provider.sdk_type:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="该平台未配置 SDK 类型（sdk_type）"
        )
    if not registry.is_supported(provider.sdk_type):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"暂不支持的 SDK 类型：{provider.sdk_type}",
        )
    return registry.get_adapter(provider.sdk_type, _load_config(provider))


def _norm_status(raw: Optional[str]) -> AssetStatus:
    return AssetStatus(raw) if raw in _VALID_STATUS else AssetStatus.UNKNOWN


def _missing_config(adapter: BaseAdapter) -> list:
    """检查适配器所需凭证是否已配置"""
    return [f for f in adapter.required_config if not adapter.config.get(f)]


def test_provider(session: Session, provider_id: int) -> dict:
    """测试平台连接 / 凭证有效性"""
    provider = _get_provider(session, provider_id)
    adapter = _build_adapter(provider)
    base = {"capabilities": adapter.capabilities(), "sdk_type": provider.sdk_type}
    missing = _missing_config(adapter)
    if missing:
        return {
            "ok": False,
            "message": f"缺少凭证配置：{', '.join(missing)}（请在平台编辑里填写 API 配置）",
            **base,
        }
    result = adapter.test_connection()
    result.update(base)
    return result


def _find_asset(session: Session, provider_id: int, external_id: str, asset_type: AssetType):
    return session.exec(
        select(Asset).where(
            Asset.provider_id == provider_id,
            Asset.external_id == external_id,
            Asset.asset_type == asset_type,
        )
    ).first()


def _sync_vps(session: Session, provider: Provider, adapter: BaseAdapter) -> dict:
    created = updated = 0
    for vps in adapter.list_vps():
        existing = _find_asset(session, provider.id, vps.external_id, AssetType.VPS)
        if existing:
            existing.name = vps.name or existing.name
            existing.status = _norm_status(vps.status)
            if vps.monthly_cost is not None:
                existing.cost = vps.monthly_cost
                existing.currency = vps.currency
            session.add(existing)
            detail = session.exec(
                select(VPSDetail).where(VPSDetail.asset_id == existing.id)
            ).first()
            if detail:
                detail.ip_address = vps.ip_address or detail.ip_address
                detail.region = vps.region or detail.region
                detail.os = vps.os or detail.os
                detail.cpu_cores = vps.cpu_cores or detail.cpu_cores
                detail.memory_gb = vps.memory_gb or detail.memory_gb
                detail.disk_gb = vps.disk_gb or detail.disk_gb
                session.add(detail)
            updated += 1
        else:
            asset = Asset(
                name=vps.name or vps.external_id,
                asset_type=AssetType.VPS,
                provider=provider.slug,
                provider_id=provider.id,
                external_id=vps.external_id,
                status=_norm_status(vps.status),
                cost=vps.monthly_cost or 0,
                currency=vps.currency,
            )
            session.add(asset)
            session.commit()
            session.refresh(asset)
            session.add(
                VPSDetail(
                    asset_id=asset.id,
                    ip_address=vps.ip_address or "",
                    region=vps.region,
                    os=vps.os,
                    cpu_cores=vps.cpu_cores or 1,
                    memory_gb=vps.memory_gb or 1,
                    disk_gb=vps.disk_gb or 20,
                )
            )
            created += 1
    session.commit()
    return {"created": created, "updated": updated}


def _sync_domains(session: Session, provider: Provider, adapter: BaseAdapter) -> dict:
    created = updated = 0
    for dom in adapter.list_domains():
        existing = _find_asset(session, provider.id, dom.external_id, AssetType.DOMAIN)
        if existing:
            existing.status = _norm_status(dom.status)
            if dom.expiry_date:
                existing.expiry_date = dom.expiry_date
            session.add(existing)
            detail = session.exec(
                select(DomainDetail).where(DomainDetail.asset_id == existing.id)
            ).first()
            if detail:
                detail.domain_name = dom.domain_name or detail.domain_name
                detail.registrar = dom.registrar or detail.registrar
                session.add(detail)
            updated += 1
        else:
            asset = Asset(
                name=dom.domain_name,
                asset_type=AssetType.DOMAIN,
                provider=provider.slug,
                provider_id=provider.id,
                external_id=dom.external_id,
                status=_norm_status(dom.status),
                expiry_date=dom.expiry_date,
            )
            session.add(asset)
            session.commit()
            session.refresh(asset)
            session.add(
                DomainDetail(
                    asset_id=asset.id,
                    domain_name=dom.domain_name,
                    registrar=dom.registrar or provider.slug,
                )
            )
            created += 1
    session.commit()
    return {"created": created, "updated": updated}


def sync_provider(session: Session, provider_id: int) -> dict:
    """同步平台资产到本地库"""
    provider = _get_provider(session, provider_id)
    adapter = _build_adapter(provider)
    missing = _missing_config(adapter)
    if missing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"缺少凭证配置：{', '.join(missing)}（请先在平台编辑里填写 API 配置）",
        )
    caps = adapter.capabilities()
    result = {"provider": provider.slug, "sdk_type": provider.sdk_type}

    if caps["list_vps"]:
        try:
            result["vps"] = _sync_vps(session, provider, adapter)
        except Exception as e:  # noqa: BLE001
            result["vps_error"] = str(e)
    if caps["list_domains"]:
        try:
            result["domains"] = _sync_domains(session, provider, adapter)
        except Exception as e:  # noqa: BLE001
            result["domains_error"] = str(e)
    if caps["get_account"]:
        try:
            result["account"] = adapter.get_account().to_dict()
        except Exception as e:  # noqa: BLE001
            result["account_error"] = str(e)

    provider.last_synced_at = datetime.utcnow()
    session.add(provider)
    session.commit()
    result["last_synced_at"] = provider.last_synced_at.isoformat()
    return result
