"""Workspaces domain - FastAPI router."""
from uuid import UUID

from fastapi import APIRouter, Depends, Path, Request

from sqlalchemy.ext.asyncio import AsyncSession

from src.config import get_settings
from src.core.app_url import resolve_app_base_url
from src.core.database import get_db
from src.domain.auth.models import User
from src.domain.auth.repository import UserRepository
from src.domain.auth.router import get_current_user
from src.domain.admin.repository import SubscriptionPlanRepository
from src.domain.billing.repository import SubscriptionRepository, WorkspaceUsageAllowanceRepository
from src.domain.workspaces.repository import (
    MembershipRepository,
    RoleRepository,
    WorkspaceInviteRepository,
    WorkspaceRepository,
    WorkspaceSettingsRepository,
)
from src.integrations.email_provider import email_transport_configured, get_email_provider
from src.domain.workspaces.member_profile import gravatar_url, member_display_name
from src.domain.workspaces.schemas import (
    InviteCreate,
    InviteCreatedResponse,
    InvitePreviewResponse,
    LocalExecutionResponse,
    LocalExecutionUpdate,
    MemberResponse,
    PendingInviteResponse,
    WorkspaceCreate,
    WorkspaceResponse,
    WorkspaceUpdate,
)
from src.domain.workspaces.service import WorkspaceService

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


async def get_workspace_service(db: AsyncSession = Depends(get_db)) -> WorkspaceService:
    settings = get_settings()
    email_provider = get_email_provider() if email_transport_configured(settings) else None
    return WorkspaceService(
        workspace_repo=WorkspaceRepository(db),
        role_repo=RoleRepository(db),
        membership_repo=MembershipRepository(db),
        invite_repo=WorkspaceInviteRepository(db),
        settings_repo=WorkspaceSettingsRepository(db),
        user_repo=UserRepository(db),
        email_provider=email_provider,
        subscription_repo=SubscriptionRepository(db),
        plan_repo=SubscriptionPlanRepository(db),
        allowance_repo=WorkspaceUsageAllowanceRepository(db),
    )


@router.post("", response_model=WorkspaceResponse)
async def create_workspace(
    body: WorkspaceCreate,
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Create workspace. Plan selection required - without subscription, app usage is blocked."""
    ws = await service.create_workspace(body.name, user.id, body.plan_slug)
    return WorkspaceResponse(
        id=ws.id,
        slug=ws.slug,
        name=ws.name,
        owner_id=ws.owner_id,
        created_at=ws.created_at,
    )


@router.get("", response_model=list[WorkspaceResponse])
async def list_workspaces(
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """List workspaces for current user."""
    workspaces = await service.list_workspaces(user.id)
    return [
        WorkspaceResponse(
            id=ws.id,
            slug=ws.slug,
            name=ws.name,
            owner_id=ws.owner_id,
            created_at=ws.created_at,
        )
        for ws in workspaces
    ]


@router.get("/{ws}", response_model=WorkspaceResponse)
async def get_workspace(
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Get workspace by ID."""
    ws_obj = await service.get_workspace(ws, user.id)
    if not ws_obj:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Workspace not found")
    return WorkspaceResponse(
        id=ws_obj.id,
        slug=ws_obj.slug,
        name=ws_obj.name,
        owner_id=ws_obj.owner_id,
        created_at=ws_obj.created_at,
    )


@router.patch("/{ws}", response_model=WorkspaceResponse)
async def update_workspace(
    body: WorkspaceUpdate,
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Update workspace. Can change name and selected_plan_slug before checkout."""
    data = body.model_dump(exclude_unset=True)
    ws_obj = await service.update_workspace(
        ws, user.id,
        name=data.get("name"),
        selected_plan_slug=data.get("selected_plan_slug"),
    )
    if not ws_obj:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Workspace not found")
    return WorkspaceResponse(
        id=ws_obj.id,
        slug=ws_obj.slug,
        name=ws_obj.name,
        owner_id=ws_obj.owner_id,
        created_at=ws_obj.created_at,
    )


@router.delete("/{ws}")
async def delete_workspace(
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Delete workspace (soft delete)."""
    await service.delete_workspace(ws, user.id)
    return {"message": "Workspace deleted"}


@router.get("/{ws}/local-execution", response_model=LocalExecutionResponse)
async def get_local_execution(
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    membership = await MembershipRepository(db).get(ws, user.id)
    if not membership:
        from src.core.exceptions import ForbiddenError
        raise ForbiddenError("You are not a member of this workspace")
    settings_row = await WorkspaceSettingsRepository(db).get_or_create(ws)
    return LocalExecutionResponse(workspace_id=ws, enabled=bool(settings_row.local_execution_enabled))


@router.patch("/{ws}/local-execution", response_model=LocalExecutionResponse)
async def patch_local_execution(
    body: LocalExecutionUpdate,
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    membership = await MembershipRepository(db).get(ws, user.id)
    if not membership:
        from src.core.exceptions import ForbiddenError
        raise ForbiddenError("You are not a member of this workspace")
    if not await MembershipRepository(db).has_permission(ws, user.id, "workspaces.manage"):
        from src.core.exceptions import ForbiddenError
        raise ForbiddenError("Workspace admin permission required to change local execution")
    settings_row = await WorkspaceSettingsRepository(db).set_local_execution_enabled(ws, body.enabled)
    return LocalExecutionResponse(workspace_id=ws, enabled=bool(settings_row.local_execution_enabled))


@router.get("/{ws}/invites", response_model=list[PendingInviteResponse])
async def list_pending_invites(
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """List pending (unexpired, unaccepted) invites. Requires ``members.manage``."""
    rows = await service.list_pending_invites(ws, user.id)
    response = []
    for inv, role in rows:
        inviter_display = await service.inviter_display(inv.invited_by) if inv.invited_by else None
        response.append(PendingInviteResponse(
            id=inv.id,
            email=inv.email,
            role_name=role.name if role else None,
            invited_by=inv.invited_by,
            invited_by_display=inviter_display,
            created_at=inv.created_at,
            expires_at=inv.expires_at,
        ))
    return response


@router.post("/{ws}/invites/{invite_id}/resend", response_model=InviteCreatedResponse)
async def resend_invite(
    request: Request,
    invite_id: UUID = Path(...),
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Revoke and replace a pending invite, then send it again."""
    base = resolve_app_base_url(request)
    inviter_display = (
        (user.display_name or "").strip()
        or (f"{user.first_name or ''} {user.last_name or ''}".strip())
        or user.email
    )
    token, email_sent, email = await service.resend_invite(
        ws, user.id, invite_id, invite_app_base_url=base, inviter_display=inviter_display
    )
    return InviteCreatedResponse(
        token=token,
        email=email,
        expires_in_days=7,
        email_sent=email_sent,
    )


@router.delete("/{ws}/invites/{invite_id}", status_code=204)
async def revoke_invite(
    invite_id: UUID = Path(...),
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Revoke a pending invite."""
    await service.revoke_invite(ws, user.id, invite_id)


@router.get("/{ws}/invites/{token}/preview", response_model=InvitePreviewResponse)
async def preview_invite(
    ws: UUID = Path(...),
    token: str = Path(...),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Read invite email and role for the public signup form."""
    inv, role = await service.preview_invite(ws, token)
    return InvitePreviewResponse(email=inv.email, role_name=role.name if role else None)


@router.post("/{ws}/invites", response_model=InviteCreatedResponse)
async def create_invite(
    request: Request,
    body: InviteCreate,
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Create workspace invite. Sends invite email when Resend/Mailgun is configured."""
    base = resolve_app_base_url(request)
    inviter_display = (
        (user.display_name or "").strip()
        or (f"{user.first_name or ''} {user.last_name or ''}".strip())
        or user.email
    )
    token, email_sent = await service.invite(
        ws,
        user.id,
        body.email,
        body.role,
        invite_app_base_url=base,
        inviter_display=inviter_display,
    )
    return InviteCreatedResponse(
        token=token,
        email=body.email,
        expires_in_days=7,
        email_sent=email_sent,
    )


@router.post("/{ws}/invites/{token}/accept", response_model=WorkspaceResponse)
async def accept_invite(
    ws: UUID = Path(...),
    token: str = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Accept invite with token. Path workspace must match invite's workspace."""
    ws_obj = await service.accept_invite(ws, token, user.id)
    if not ws_obj:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Invalid invite")
    return WorkspaceResponse(
        id=ws_obj.id,
        slug=ws_obj.slug,
        name=ws_obj.name,
        owner_id=ws_obj.owner_id,
        created_at=ws_obj.created_at,
    )


@router.patch("/{ws}/members/{user_id}")
async def update_member(
    body: dict,  # {"role": "editor"}
    ws: UUID = Path(...),
    user_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Update member role."""
    role = body.get("role", "editor")
    await service.update_member_role(ws, user.id, user_id, role)
    return {"message": "Member updated"}


@router.delete("/{ws}/members/{user_id}")
async def remove_member(
    ws: UUID = Path(...),
    user_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """Remove member from workspace."""
    await service.remove_member(ws, user.id, user_id)
    return {"message": "Member removed"}


@router.get("/{ws}/members", response_model=list[MemberResponse])
async def list_members(
    ws: UUID = Path(...),
    user: User = Depends(get_current_user),
    service: WorkspaceService = Depends(get_workspace_service),
):
    """List workspace members."""
    members = await service.list_members(ws, user.id)
    return [
        MemberResponse(
            user_id=m.user_id,
            email=u.email,
            name=member_display_name(u),
            avatar_url=u.avatar_url,
            gravatar_url=gravatar_url(u.email),
            role_id=m.role_id,
            role_name=r.name if r else None,
            joined_at=m.joined_at,
        )
        for m, r, u in members
    ]
