"""Commercial Runtime API — discovery, generic registries, engines, tenant ops."""
from __future__ import annotations

from typing import Any
from uuid import UUID

from fastapi import APIRouter, Body, Depends, Query, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, get_pagination
from app.commercial.recommendation import AssessmentEngine, RecommendationEngine
from app.commercial.resolvers import BundleResolver, LicenseResolver, PlanResolver
from app.commercial.service import CommercialRegistryService
from app.core.security import (
    get_optional_user,
    require_authenticated,
    require_platform_admin,
)
from app.models.commercial import CommercialActivationState
from shared.pagination import PaginationParams
from shared.security import CurrentUser

router = APIRouter(prefix="/commercial", tags=["commercial"])


def _actor_id(user: CurrentUser | None) -> UUID | None:
    if user is None:
        return None
    try:
        return UUID(str(user.user_id))
    except Exception:  # noqa: BLE001
        return None


# ── Discovery ──────────────────────────────────────────────────────────────


@router.get("/catalog")
async def commercial_catalog(db: AsyncSession = Depends(get_db)) -> dict[str, Any]:
    return await CommercialRegistryService(db).discovery_catalog()


@router.get("/health")
async def commercial_health() -> dict[str, str]:
    return {"status": "ok", "domain": "commercial-runtime", "version": "1.0.0"}


# ── Assessment / Recommendations ───────────────────────────────────────────


@router.get("/assessment/schema")
async def assessment_schema(
    schema_code: str | None = None,
    db: AsyncSession = Depends(get_db),
) -> dict[str, Any]:
    return await AssessmentEngine(db).get_schema(schema_code)


@router.post("/recommendations")
async def recommendations(
    body: dict[str, Any] = Body(default_factory=dict),
    db: AsyncSession = Depends(get_db),
    _user=Depends(get_optional_user),
) -> dict[str, Any]:
    return await RecommendationEngine(db).evaluate(body)


@router.get("/recommendations/tenant")
async def tenant_recommendations(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    # Tenant feed = evaluate with subscription context hints
    lic = LicenseResolver(db)
    sub = await lic.get_subscription(tenant_id)
    req = {
        "tenant_id": str(tenant_id),
        "bundle_code": sub.bundle_code if sub else None,
        "plan_code": sub.plan_code if sub else None,
    }
    result = await RecommendationEngine(db).evaluate(req)
    return {
        "recommended_products": result.get("recommended_products") or [],
        "recommended_bundles": result.get("recommended_bundles") or [],
        "recommended_services": result.get("recommended_services") or [],
        "recommended_upgrades": result.get("recommended_pricing") or [],
        "recommended_automation_packs": result.get("recommended_automation_packs") or [],
        "recommended_extensions": [],
        "rule_trace": result.get("rule_trace") or [],
    }


# ── Resolvers ──────────────────────────────────────────────────────────────


@router.get("/bundles/{bundle_code}/resolve")
async def resolve_bundle(bundle_code: str, db: AsyncSession = Depends(get_db)) -> dict[str, Any]:
    return await BundleResolver(db).resolve(bundle_code)


@router.get("/plans/{plan_code}/resolve")
async def resolve_plan(plan_code: str, db: AsyncSession = Depends(get_db)) -> dict[str, Any]:
    return await PlanResolver(db).resolve(plan_code)


@router.post("/entitlements/check")
async def entitlements_check(
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    tenant_id = UUID(str(body.get("tenant_id")))
    feature_key = str(body.get("feature_key") or body.get("capability_code") or "")
    return await LicenseResolver(db).check_entitlement(tenant_id, feature_key)


@router.post("/subscriptions")
async def create_subscription(
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_authenticated),
) -> dict[str, Any]:
    tenant_id = UUID(str(body.get("tenant_id")))
    return await LicenseResolver(db).activate(
        tenant_id,
        plan_code=body.get("plan_code"),
        bundle_code=body.get("bundle_code"),
        pricing_item_code=body.get("pricing_item_code"),
        status=str(body.get("status") or "trialing"),
        actor=_actor_id(user),
    )


@router.get("/licenses")
async def list_licenses(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    rows = await LicenseResolver(db).list_licenses(tenant_id)
    items = [
        {
            "license_code": r.license_code,
            "display_name": r.display_name,
            "status": r.status,
            "capability_codes": r.capability_codes,
            "product_codes": r.product_codes,
            "bundle_code": r.bundle_code,
            "quota": r.quota,
            "expires_at": r.expires_at.isoformat() if r.expires_at else None,
        }
        for r in rows
    ]
    return {"items": items, "licenses": items}


@router.get("/dashboard")
async def commercial_dashboard(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    lic = LicenseResolver(db)
    sub = await lic.get_subscription(tenant_id)
    licenses = await lic.list_licenses(tenant_id)
    return {
        "tenant_id": str(tenant_id),
        "subscription": {
            "status": sub.status if sub else None,
            "plan_code": sub.plan_code if sub else None,
            "bundle_code": sub.bundle_code if sub else None,
            "trial_ends_at": sub.trial_ends_at.isoformat() if sub and sub.trial_ends_at else None,
        }
        if sub
        else None,
        "licenses": [
            {
                "license_code": r.license_code,
                "display_name": r.display_name,
                "status": r.status,
            }
            for r in licenses
        ],
    }


@router.get("/activation")
async def activation_pipeline(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    stmt = select(CommercialActivationState).where(
        CommercialActivationState.tenant_id == tenant_id
    )
    state = (await db.execute(stmt)).scalar_one_or_none()
    if state is None:
        return {"status": "pending", "completion_percent": 0, "steps": []}
    return {
        "status": state.status,
        "completion_percent": state.completion_percent,
        "steps": state.steps,
    }


@router.get("/checklist")
async def setup_checklist(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    stmt = select(CommercialActivationState).where(
        CommercialActivationState.tenant_id == tenant_id
    )
    state = (await db.execute(stmt)).scalar_one_or_none()
    items = state.checklist if state else []
    done = sum(1 for i in items if i.get("done"))
    pct = int((done / len(items)) * 100) if items else 0
    return {"items": items, "completion_percent": pct}


@router.get("/usage")
async def usage_counters(
    tenant_id: UUID = Query(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    licenses = await LicenseResolver(db).list_licenses(tenant_id)
    counters = []
    for lic in licenses:
        for key, val in (lic.quota or {}).items():
            if isinstance(val, dict):
                counters.append(
                    {
                        "key": key,
                        "label": val.get("label") or key,
                        "used": val.get("used", 0),
                        "limit": val.get("limit"),
                        "unit": val.get("unit"),
                    }
                )
            else:
                counters.append({"key": key, "label": key, "used": 0, "limit": val})
    return {"items": counters}


@router.get("/invoices")
async def invoices_placeholder(
    tenant_id: UUID = Query(...),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    # Commercial owns subscription/license truth; payment invoices stay in Payment.
    # Empty envelope — never fake invoices.
    return {
        "items": [],
        "message": "فاکتورهای مالی در سرویس Payment هستند؛ Commercial فقط refs نگه‌می‌دارد.",
    }


@router.get("/transactions")
async def transactions_placeholder(
    tenant_id: UUID = Query(...),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    return {
        "items": [],
        "message": "تراکنش‌های پرداخت در سرویس Payment هستند.",
    }


@router.post("/policies/evaluate")
async def evaluate_policy(
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    _user=Depends(require_authenticated),
) -> dict[str, Any]:
    policy_code = str(body.get("policy_code") or body.get("code") or "domain.custom")
    svc = CommercialRegistryService(db)
    rows, _ = await svc.repo.list_objects("policies", status="published", platform_only=True, limit=200)
    matched = None
    for r in rows:
        if r.stable_code == policy_code or (r.payload or {}).get("target") == body.get("target"):
            matched = r
            break
    if matched is None:
        return {
            "custom_domain_allowed": False,
            "subdomain_only": True,
            "reason": "سیاست دامنه منتشرشده یافت نشد — پیش‌فرض subdomain_only",
            "source": "commercial.default",
        }
    payload = dict(matched.payload or {})
    return {
        "custom_domain_allowed": bool(payload.get("custom_domain_allowed", False)),
        "subdomain_only": bool(payload.get("subdomain_only", True)),
        "reason": payload.get("reason") or matched.description,
        "parameters": payload.get("parameters") or {},
        "source": matched.stable_code,
        "ssl_ready": payload.get("ssl_ready"),
        "dns_instructions": payload.get("dns_instructions") or [],
        "verification_state": payload.get("verification_state"),
    }


# ── Generic registry CRUD ──────────────────────────────────────────────────


async def _list_registry(
    path: str,
    *,
    db: AsyncSession,
    pagination: PaginationParams,
    q: str | None,
    status_filter: str | None,
    sort: str,
    order: str,
    admin: bool,
) -> dict[str, Any]:
    return await CommercialRegistryService(db).list(
        path,
        q=q,
        status=status_filter,
        sort=sort,
        order=order,
        offset=pagination.offset,
        limit=pagination.limit,
        admin=admin,
    )


def _register_kind_routes(path: str) -> None:
    @router.get(f"/{path}")
    async def list_items(  # type: ignore[no-redef]
        pagination: PaginationParams = Depends(get_pagination),
        q: str | None = None,
        status: str | None = Query(default="published", alias="status"),
        sort: str = "display_name",
        order: str = "asc",
        db: AsyncSession = Depends(get_db),
        user: CurrentUser | None = Depends(get_optional_user),
        _path: str = path,
    ) -> dict[str, Any]:
        admin = bool(user and user.has_role("platform_admin"))
        return await _list_registry(
            _path,
            db=db,
            pagination=pagination,
            q=q,
            status_filter=status,
            sort=sort,
            order=order,
            admin=admin,
        )

    @router.get(f"/{path}/{{object_id}}")
    async def get_item(  # type: ignore[no-redef]
        object_id: UUID,
        db: AsyncSession = Depends(get_db),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).get(_path, object_id)

    @router.post(f"/{path}", status_code=status.HTTP_201_CREATED)
    async def create_item(  # type: ignore[no-redef]
        body: dict[str, Any] = Body(...),
        db: AsyncSession = Depends(get_db),
        user: CurrentUser = Depends(require_platform_admin),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).create(_path, body, actor=_actor_id(user))

    @router.patch(f"/{path}/{{object_id}}")
    async def patch_item(  # type: ignore[no-redef]
        object_id: UUID,
        body: dict[str, Any] = Body(...),
        db: AsyncSession = Depends(get_db),
        user: CurrentUser = Depends(require_platform_admin),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).update(_path, object_id, body, actor=_actor_id(user))

    @router.put(f"/{path}/{{object_id}}")
    async def put_item(  # type: ignore[no-redef]
        object_id: UUID,
        body: dict[str, Any] = Body(...),
        db: AsyncSession = Depends(get_db),
        user: CurrentUser = Depends(require_platform_admin),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).update(_path, object_id, body, actor=_actor_id(user))

    @router.delete(f"/{path}/{{object_id}}", status_code=status.HTTP_200_OK)
    async def delete_item(  # type: ignore[no-redef]
        object_id: UUID,
        db: AsyncSession = Depends(get_db),
        user: CurrentUser = Depends(require_platform_admin),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).lifecycle(
            _path, object_id, "delete", actor=_actor_id(user)
        )

    @router.post(f"/{path}/{{object_id}}/{{action}}")
    async def lifecycle_item(  # type: ignore[no-redef]
        object_id: UUID,
        action: str,
        db: AsyncSession = Depends(get_db),
        user: CurrentUser = Depends(require_platform_admin),
        _path: str = path,
    ) -> dict[str, Any]:
        return await CommercialRegistryService(db).lifecycle(
            _path, object_id, action, actor=_actor_id(user)
        )


# Built-in FE-compatible paths
for _path in (
    "products",
    "bundles",
    "pricing",
    "plans",
    "trials",
    "capabilities",
    "policies",
    "assets",
    "extensions",
    "automation-packs",
    "metadata",
    "recommendation-rules",
    "assessment-schemas",
    "notifications",
    "usage-plans",
    "coupons",
    "promotions",
    "taxes",
    "currencies",
    "regions",
    "industries",
    "business-types",
    "announcements",
    "languages",
):
    _register_kind_routes(_path)


# Generic unlimited path for future kinds without code change to this list:
@router.get("/registries/{kind}")
async def list_generic_registry(
    kind: str,
    pagination: PaginationParams = Depends(get_pagination),
    q: str | None = None,
    status: str | None = Query(default="published", alias="status"),
    sort: str = "display_name",
    order: str = "asc",
    db: AsyncSession = Depends(get_db),
    user: CurrentUser | None = Depends(get_optional_user),
) -> dict[str, Any]:
    admin = bool(user and user.has_role("platform_admin"))
    return await _list_registry(
        kind,
        db=db,
        pagination=pagination,
        q=q,
        status_filter=status,
        sort=sort,
        order=order,
        admin=admin,
    )


@router.post("/registries/{kind}", status_code=status.HTTP_201_CREATED)
async def create_generic_registry(
    kind: str,
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_platform_admin),
) -> dict[str, Any]:
    return await CommercialRegistryService(db).create(kind, body, actor=_actor_id(user))


@router.get("/registries/{kind}/{object_id}")
async def get_generic_registry(
    kind: str,
    object_id: UUID,
    db: AsyncSession = Depends(get_db),
) -> dict[str, Any]:
    return await CommercialRegistryService(db).get(kind, object_id)


@router.patch("/registries/{kind}/{object_id}")
async def patch_generic_registry(
    kind: str,
    object_id: UUID,
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_platform_admin),
) -> dict[str, Any]:
    return await CommercialRegistryService(db).update(kind, object_id, body, actor=_actor_id(user))


@router.delete("/registries/{kind}/{object_id}")
async def delete_generic_registry(
    kind: str,
    object_id: UUID,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_platform_admin),
) -> dict[str, Any]:
    return await CommercialRegistryService(db).lifecycle(
        kind, object_id, "delete", actor=_actor_id(user)
    )


@router.post("/registries/{kind}/{object_id}/{action}")
async def lifecycle_generic_registry(
    kind: str,
    object_id: UUID,
    action: str,
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_platform_admin),
) -> dict[str, Any]:
    return await CommercialRegistryService(db).lifecycle(
        kind, object_id, action, actor=_actor_id(user)
    )


@router.post("/admin/kinds", status_code=status.HTTP_201_CREATED)
async def register_kind(
    body: dict[str, Any] = Body(...),
    db: AsyncSession = Depends(get_db),
    user: CurrentUser = Depends(require_platform_admin),
) -> dict[str, Any]:
    """Register a brand-new registry kind (unlimited future expansion)."""
    from app.models.commercial import CommercialRegistryKind

    svc = CommercialRegistryService(db)
    kind = await svc.repo.upsert_kind(
        CommercialRegistryKind(
            kind=str(body["kind"]),
            path=str(body.get("path") or body["kind"]),
            display_name=str(body.get("display_name") or body["kind"]),
            description=body.get("description"),
            code_field=str(body.get("code_field") or "code"),
            list_envelope=str(body.get("list_envelope") or "items"),
            public_read=bool(body.get("public_read", True)),
            enabled=bool(body.get("enabled", True)),
            sort_order=int(body.get("sort_order") or 1000),
            meta_data=body.get("metadata"),
        )
    )
    await db.commit()
    return {
        "kind": kind.kind,
        "path": kind.path,
        "href": f"/api/v1/commercial/registries/{kind.kind}",
        "display_name": kind.display_name,
    }
