from __future__ import annotations

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.types import ASGIApp

from app.core.db.common import CommonSessionLocal
from app.modules.domain_management.services import normalize_request_host, resolve_domain_context


class DomainResolverMiddleware(BaseHTTPMiddleware):
    """Resolve request host to platform / tenant / consultant context.

    Phase 7T.2 is intentionally read-only:
    - It does not redirect users.
    - It does not change database records.
    - It does not override logged-in user permissions.
    - It only exposes a trusted runtime context on request.state.

    Later phases use this context for branding, marketplace mode, tenant subdomains,
    consultant domains, and custom domain verification.
    """

    def __init__(self, app: ASGIApp) -> None:
        super().__init__(app)

    async def dispatch(self, request: Request, call_next):
        host_header = request.headers.get("x-forwarded-host") or request.headers.get("host")
        host = normalize_request_host(host_header)

        # Safe defaults; every template/route can read these without checking existence.
        request.state.request_host = host
        request.state.domain_resolved = False
        request.state.domain_mapping_id = None
        request.state.domain_name = host
        request.state.domain_type = None
        request.state.domain_tenant_id = None
        request.state.domain_tenant_code = None
        request.state.domain_branch_id = None
        request.state.domain_branch_code = None
        request.state.domain_consultant_id = None
        request.state.domain_parent_tenant_id = None
        request.state.domain_is_verified = False
        request.state.domain_status = None
        request.state.domain_context = {
            "is_resolved": False,
            "host": host,
            "mapping_id": None,
            "domain_name": host,
            "domain_type": None,
            "tenant_id": None,
            "tenant_code": None,
            "branch_id": None,
            "branch_code": None,
            "consultant_id": None,
            "parent_tenant_id": None,
            "is_verified": False,
            "status": None,
        }

        # Static files and empty/invalid host can proceed without DB lookup.
        if host and not request.url.path.startswith("/static/"):
            db = CommonSessionLocal()
            try:
                resolved = resolve_domain_context(db, host)
                if resolved.is_resolved:
                    request.state.domain_resolved = True
                    request.state.domain_mapping_id = resolved.mapping_id
                    request.state.domain_name = resolved.domain_name
                    request.state.domain_type = resolved.domain_type
                    request.state.domain_tenant_id = resolved.tenant_id
                    request.state.domain_tenant_code = resolved.tenant_code
                    request.state.domain_branch_id = resolved.branch_id
                    request.state.domain_branch_code = resolved.branch_code
                    request.state.domain_consultant_id = resolved.consultant_id
                    request.state.domain_parent_tenant_id = resolved.parent_tenant_id
                    request.state.domain_is_verified = resolved.is_verified
                    request.state.domain_status = resolved.status
                    request.state.domain_context = {
                        "is_resolved": True,
                        "host": resolved.host,
                        "mapping_id": resolved.mapping_id,
                        "domain_name": resolved.domain_name,
                        "domain_type": resolved.domain_type,
                        "tenant_id": resolved.tenant_id,
                        "tenant_code": resolved.tenant_code,
                        "branch_id": resolved.branch_id,
                        "branch_code": resolved.branch_code,
                        "consultant_id": resolved.consultant_id,
                        "parent_tenant_id": resolved.parent_tenant_id,
                        "is_verified": resolved.is_verified,
                        "status": resolved.status,
                    }
            except Exception:
                # Domain resolution must never take the ERP down. If the domain table is
                # missing during deployment or DB is temporarily unavailable, continue
                # with the normal default context.
                pass
            finally:
                db.close()

        response = await call_next(request)
        if getattr(request.state, "domain_resolved", False):
            response.headers["X-AuditFirm-Domain-Resolved"] = "1"
            response.headers["X-AuditFirm-Domain-Type"] = str(getattr(request.state, "domain_type", "") or "")
        return response
