"""
Workspace API — team workspaces with seat-based membership.

Business plan includes 5 seats (models.subscription.PLANS); the seat limit
is enforced here. Owners/admins manage members; glossaries can be shared
with a workspace (glossaries.workspace_id).

Endpoints:
  POST   /api/v1/workspaces                        create (owner membership)
  GET    /api/v1/workspaces                        list mine (with members)
  POST   /api/v1/workspaces/{id}/members           add member by email
  DELETE /api/v1/workspaces/{id}/members/{user_id} remove member
"""

from typing import Optional

from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

from core.logging import get_logger
from database.connection import get_sync_session
from database.models import User, Workspace, WorkspaceMember
from middleware.api_key_auth import get_authenticated_user
from models.subscription import PlanType, PLANS

logger = get_logger(__name__)

router = APIRouter(prefix="/api/v1/workspaces", tags=["Workspaces"])

VALID_ROLES = {"admin", "member"}


def _seat_limit_for_owner(plan) -> int:
    """Seats allowed for the workspace owner's plan (Business/Enterprise)."""
    try:
        plan_cfg = PLANS.get(PlanType(plan))
    except (ValueError, TypeError):
        plan_cfg = None
    seats = (plan_cfg or {}).get("team_seats", 0) or 0
    return seats if seats > 0 else 0  # -1 (enterprise) treated as unlimited


def _seats_unlimited(plan) -> bool:
    try:
        return PlanType(plan) == PlanType.ENTERPRISE
    except (ValueError, TypeError):
        return False


class WorkspaceCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)


class MemberAdd(BaseModel):
    email: str = Field(..., min_length=3)
    role: str = Field("member", description="admin | member")


@router.post("", status_code=201)
async def create_workspace(
    payload: WorkspaceCreate,
    current_user=Depends(get_authenticated_user),
):
    if not current_user:
        raise HTTPException(status_code=401, detail={"error": "AUTH_REQUIRED"})
    if not _seats_unlimited(current_user.plan) and _seat_limit_for_owner(current_user.plan) == 0:
        raise HTTPException(
            status_code=403,
            detail={
                "error": "PLAN_REQUIRED",
                "message": "Les espaces de travail nécessitent le plan Business.",
            },
        )

    def _create():
        with get_sync_session() as session:
            ws = Workspace(name=payload.name.strip(), owner_id=str(current_user.id))
            session.add(ws)
            session.flush()
            session.add(
                WorkspaceMember(
                    workspace_id=ws.id,
                    user_id=str(current_user.id),
                    role="owner",
                )
            )
            session.commit()
            session.refresh(ws)
            return ws.to_dict()

    from asyncio import to_thread

    data = await to_thread(_create)
    return JSONResponse(status_code=201, content={"data": data, "meta": {}})


@router.get("")
async def list_workspaces(current_user=Depends(get_authenticated_user)):
    if not current_user:
        raise HTTPException(status_code=401, detail={"error": "AUTH_REQUIRED"})

    def _list():
        with get_sync_session() as session:
            memberships = (
                session.query(WorkspaceMember)
                .filter(WorkspaceMember.user_id == str(current_user.id))
                .all()
            )
            result = []
            for m in memberships:
                ws = (
                    session.query(Workspace)
                    .filter(Workspace.id == m.workspace_id)
                    .first()
                )
                if not ws:
                    continue
                members = (
                    session.query(WorkspaceMember)
                    .filter(WorkspaceMember.workspace_id == ws.id)
                    .all()
                )
                enriched = {
                    **ws.to_dict(),
                    "my_role": m.role,
                    "member_count": len(members),
                    "seat_limit": (
                        -1
                        if _seats_unlimited(current_user.plan)
                        else _seat_limit_for_owner(current_user.plan)
                    ),
                }
                result.append(enriched)
            return result

    from asyncio import to_thread

    data = await to_thread(_list)
    return JSONResponse(status_code=200, content={"data": data, "meta": {}})


@router.post("/{workspace_id}/members", status_code=201)
async def add_member(
    workspace_id: str,
    payload: MemberAdd,
    current_user=Depends(get_authenticated_user),
):
    if not current_user:
        raise HTTPException(status_code=401, detail={"error": "AUTH_REQUIRED"})
    if payload.role not in VALID_ROLES:
        raise HTTPException(
            status_code=422, detail={"error": "INVALID_ROLE"}
        )

    def _add():
        with get_sync_session() as session:
            ws = (
                session.query(Workspace)
                .filter(Workspace.id == workspace_id)
                .first()
            )
            if not ws:
                return ("not_found", None)
            me = (
                session.query(WorkspaceMember)
                .filter(
                    WorkspaceMember.workspace_id == workspace_id,
                    WorkspaceMember.user_id == str(current_user.id),
                )
                .first()
            )
            if not me or me.role not in ("owner", "admin"):
                return ("forbidden", None)

            # Seat enforcement (owner's plan)
            if ws.owner_id == str(current_user.id):
                owner_plan = current_user.plan
            else:
                owner = session.query(User).filter(User.id == ws.owner_id).first()
                owner_plan = getattr(owner, "plan", None)
            count = (
                session.query(WorkspaceMember)
                .filter(WorkspaceMember.workspace_id == workspace_id)
                .count()
            )
            if not _seats_unlimited(owner_plan) and count >= _seat_limit_for_owner(owner_plan):
                return ("seat_limit", count)

            target = (
                session.query(User)
                .filter(User.email == payload.email.strip().lower())
                .first()
            )
            if not target:
                return ("user_not_found", None)
            existing = (
                session.query(WorkspaceMember)
                .filter(
                    WorkspaceMember.workspace_id == workspace_id,
                    WorkspaceMember.user_id == str(target.id),
                )
                .first()
            )
            if existing:
                return ("already_member", None)

            member = WorkspaceMember(
                workspace_id=workspace_id,
                user_id=str(target.id),
                role=payload.role,
            )
            session.add(member)
            session.commit()
            session.refresh(member)
            return ("ok", member.to_dict())

    from asyncio import to_thread

    status, payload_out = await to_thread(_add)
    if status == "not_found":
        raise HTTPException(status_code=404, detail={"error": "WORKSPACE_NOT_FOUND"})
    if status == "forbidden":
        raise HTTPException(status_code=403, detail={"error": "ACCESS_DENIED"})
    if status == "seat_limit":
        raise HTTPException(
            status_code=409,
            detail={
                "error": "SEAT_LIMIT_REACHED",
                "message": "Limite de sièges du plan atteinte. Passez au plan supérieur pour ajouter des membres.",
                "details": {"seats_used": payload_out},
            },
        )
    if status == "user_not_found":
        raise HTTPException(
            status_code=404,
            detail={
                "error": "USER_NOT_FOUND",
                "message": "Aucun compte avec cet e-mail — l'utilisateur doit d'abord créer un compte.",
            },
        )
    if status == "already_member":
        raise HTTPException(status_code=409, detail={"error": "ALREADY_MEMBER"})

    return JSONResponse(status_code=201, content={"data": payload_out, "meta": {}})


@router.delete("/{workspace_id}/members/{user_id}", status_code=200)
async def remove_member(
    workspace_id: str,
    user_id: str,
    current_user=Depends(get_authenticated_user),
):
    if not current_user:
        raise HTTPException(status_code=401, detail={"error": "AUTH_REQUIRED"})

    def _remove():
        with get_sync_session() as session:
            me = (
                session.query(WorkspaceMember)
                .filter(
                    WorkspaceMember.workspace_id == workspace_id,
                    WorkspaceMember.user_id == str(current_user.id),
                )
                .first()
            )
            if not me or me.role not in ("owner", "admin"):
                return "forbidden"
            target = (
                session.query(WorkspaceMember)
                .filter(
                    WorkspaceMember.workspace_id == workspace_id,
                    WorkspaceMember.user_id == user_id,
                )
                .first()
            )
            if not target:
                return "not_found"
            if target.role == "owner":
                return "owner_immutable"
            session.delete(target)
            session.commit()
            return "ok"

    from asyncio import to_thread

    status = await to_thread(_remove)
    if status == "forbidden":
        raise HTTPException(status_code=403, detail={"error": "ACCESS_DENIED"})
    if status == "not_found":
        raise HTTPException(status_code=404, detail={"error": "MEMBER_NOT_FOUND"})
    if status == "owner_immutable":
        raise HTTPException(
            status_code=422,
            detail={"error": "OWNER_IMMUTABLE", "message": "Le propriétaire ne peut pas être retiré."},
        )

    return JSONResponse(
        status_code=200, content={"data": {"removed": True}, "meta": {}}
    )
