"""租户 L1 上行 stub — POST /v1/tenant/push · NAS mirror（非 L2）。"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal
from fastapi import APIRouter, HTTPException, Request

from pydantic import BaseModel, Field
from niannian.tenant.context import RequestContext, resolve_request_context
from niannian.tenant.l1_paths import (
    L1_TREE_DATA,
    L1_TREE_TENANT_CONFIG,
    mirror_file_path,
    nas_mirror_root,
    validate_relative_file_path,
)
from niannian.tenant.sessions import TenantSessionStore

if TYPE_CHECKING:
    from niannian.client import NianNian

PUSH_CAPABILITY = "tenant.push.upstream"


class PushFileItem(BaseModel):
    path: str = Field(..., min_length=1)
    content: str = ""


class TenantPushBody(BaseModel):
    tree: Literal["data", "tenant_config"]
    files: list[PushFileItem] = Field(..., min_length=1)


class RequireTenantPush:
    def __init__(self, nn: NianNian, sessions: TenantSessionStore) -> None:
        self._nn = nn
        self._sessions = sessions

    def __call__(self, request: Request) -> RequestContext:
        ctx = resolve_request_context(
            request,
            self._nn._config,
            home=self._nn._home,
            sessions=self._sessions,
        )
        if not ctx.session_token:
            raise HTTPException(
                status_code=403,
                detail={"code": "tenant_session_required", "message": "valid tenant X-NianNian-Session required"},
            )
        if ctx.role != "tenant":
            raise HTTPException(
                status_code=403,
                detail={"code": "tenant_only", "message": "tenant session required for push"},
            )
        if PUSH_CAPABILITY not in ctx.capabilities:
            raise HTTPException(
                status_code=403,
                detail={"code": "capability_denied", "message": f"missing capability {PUSH_CAPABILITY}"},
            )
        return ctx


def create_tenant_push_router(nn: NianNian) -> APIRouter:
    router = APIRouter(prefix="/v1/tenant", tags=["tenant"])
    sessions = TenantSessionStore(nn._home)
    require_tenant_push = RequireTenantPush(nn, sessions)

    @router.post("/push")
    def tenant_push(body: TenantPushBody, request: Request) -> dict[str, Any]:
        ctx = require_tenant_push(request)
        tree = body.tree
        if tree not in (L1_TREE_DATA, L1_TREE_TENANT_CONFIG):
            raise HTTPException(
                status_code=400,
                detail={"code": "invalid_tree", "message": f"tree must be {L1_TREE_DATA!r} or {L1_TREE_TENANT_CONFIG!r}"},
            )

        written: list[str] = []
        for item in body.files:
            try:
                rel = validate_relative_file_path(item.path, tree=tree)
                target = mirror_file_path(nn._home, tree, ctx.user_id, rel)
            except ValueError as exc:
                raise HTTPException(
                    status_code=400,
                    detail={"code": "invalid_path", "message": str(exc)},
                ) from exc
            target.parent.mkdir(parents=True, exist_ok=True)
            target.write_text(item.content, encoding="utf-8")
            written.append(rel)

        mirror_root = nas_mirror_root(nn._home)
        return {
            "username": ctx.user_id,
            "tree": tree,
            "written": written,
            "mirror_root": str(mirror_root),
        }

    return router
