"""
TenantMiddleware
----------------
Extracts company_id from the JWT on every request and stores it in
request.state.company_id.  Route handlers and service functions that
need to enforce tenant isolation can read this value without re-decoding
the token.

Cross-company data access is blocked at the query level: any service that
lists branches for the current user should filter by
  Branch.company_id == request.state.company_id
This ensures transactions, products, customers, etc. are never mixed
between tenants even when branch_id values happen to collide.
"""
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response
from jose import jwt, JWTError

# These paths bypass company validation entirely
_OPEN_PATHS = {
    "/docs", "/redoc", "/openapi.json",
    "/health", "/health/db", "/metrics",
    "/api/v1/auth/login-json",
    "/api/v1/auth/login-direct",
    "/api/v1/auth/login-test",
    "/api/v1/auth/login-branches",
    "/api/v1/auth/login-branches/health",
    "/api/v1/auth/login-config",
    "/api/v1/auth/login-workspace",
    "/api/v1/companies/register",
    "/api/v1/companies/register-full",
    "/api/v1/companies/check-setup",
    "/api/v1/licensing/validate",
    "/api/v1/licensing/nodes/register",
    "/api/v1/licensing/nodes/heartbeat",
    "/api/v1/sync/ingest",
    "/api/v1/licensing/verify-setup",
    "/api/v1/licensing/claim-setup",
    "/api/v1/platform/auth/login",
    "/install/local",
}


class TenantMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, secret_key: str, algorithm: str = "HS256"):
        super().__init__(app)
        self._secret = secret_key
        self._algo = algorithm

    async def dispatch(self, request: Request, call_next) -> Response:
        request.state.company_id = None

        path = request.url.path

        # Static files and open endpoints — skip
        if path.startswith("/static") or path in _OPEN_PATHS or path.startswith("/api/v1/installer/"):
            return await call_next(request)

        # Company-lookup is also open
        if path.startswith("/api/v1/companies/lookup/"):
            return await call_next(request)

        # Try to extract company_id from the bearer token
        auth_header = request.headers.get("Authorization", "")
        if auth_header.startswith("Bearer "):
            token = auth_header[7:]
            try:
                payload = jwt.decode(token, self._secret, algorithms=[self._algo])
                company_id = payload.get("company_id")
                if company_id:
                    request.state.company_id = company_id
            except JWTError:
                pass  # Invalid token will be caught by get_current_user dependency

        return await call_next(request)
