"""Organization API routes.

⚠️ AUTO-GENERATED BY PRISM (GENERATE_ONCE)
Organization CRUD, member management, and invitation endpoints.
"""

from __future__ import annotations

import logging
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from {{ project_name }}.database import get_db
from {{ project_name }}.middleware.auth import CurrentActiveUser
from {{ project_name }}.middleware.organization import (
    require_org_permission,
    get_org_membership,
)
from {{ project_name }}.organization.org_service import (
    accept_invitation,
    add_member,
    count_members,
    create_invitation,
    create_organization,
    delete_organization,
    get_membership,
    get_organization_by_id,
    get_organization_by_slug,
    list_members,
    list_org_invitations,
    list_user_organizations,
    remove_member,
    revoke_invitation,
    update_member_role,
    update_organization,
    ORG_ROLES,
)
from {{ project_name }}.schemas.organization import (
    AcceptInvitationRequest,
    AddMemberRequest,
    InvitationCreateRequest,
    InvitationResponse,
    MemberListResponse,
    MemberResponse,
    OrganizationCreateRequest,
    OrganizationListResponse,
    OrganizationResponse,
    OrganizationUpdateRequest,
    OrgRoleResponse,
    UpdateMemberRoleRequest,
)

logger = logging.getLogger(__name__)

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


# ── Organization CRUD ────────────────────────────────────────────


@router.post("/", response_model=OrganizationResponse, status_code=status.HTTP_201_CREATED)
async def create_org(
    body: OrganizationCreateRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> OrganizationResponse:
    """Create a new organization. The creating user becomes the owner."""
{% if not allow_multiple_orgs %}
    # Check if user already belongs to an organization
    user_orgs = await list_user_organizations(db, current_user.id)
    if user_orgs:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Users can only belong to one organization",
        )
{% endif %}
    org = await create_organization(
        db,
        name=body.name,
        slug=body.slug,
        description=body.description,
        created_by_id=current_user.id,
    )
    member_count = await count_members(db, org.id)
    resp = OrganizationResponse.model_validate(org)
    resp.member_count = member_count
    resp.current_user_role = "owner"
    return resp


@router.get("/", response_model=OrganizationListResponse)
async def list_my_orgs(
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
    skip: int = 0,
    limit: int = 50,
) -> OrganizationListResponse:
    """List organizations the current user belongs to."""
    user_orgs = await list_user_organizations(db, current_user.id)
    orgs = []
    for org, role in user_orgs[skip : skip + limit]:
        resp = OrganizationResponse.model_validate(org)
        resp.current_user_role = role
        member_count = await count_members(db, org.id)
        resp.member_count = member_count
        orgs.append(resp)
    return OrganizationListResponse(
        organizations=orgs,
        total=len(user_orgs),
        skip=skip,
        limit=limit,
    )


@router.get("/{org_slug}", response_model=OrganizationResponse)
async def get_org(
    org_slug: str,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> OrganizationResponse:
    """Get organization details by slug."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_membership(db, org.id, current_user.id)
    if not membership or not membership.is_active:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not a member of this organization")

    member_count = await count_members(db, org.id)
    resp = OrganizationResponse.model_validate(org)
    resp.member_count = member_count
    resp.current_user_role = membership.role
    return resp


@router.patch("/{org_slug}", response_model=OrganizationResponse)
async def update_org(
    org_slug: str,
    body: OrganizationUpdateRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> OrganizationResponse:
    """Update organization details. Requires settings.edit permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "settings.edit")

    org = await update_organization(
        db, org.id,
        name=body.name,
        description=body.description,
        avatar_url=body.avatar_url,
    )
    member_count = await count_members(db, org.id)
    resp = OrganizationResponse.model_validate(org)
    resp.member_count = member_count
    resp.current_user_role = membership.role
    return resp


@router.delete("/{org_slug}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_org(
    org_slug: str,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Delete an organization. Only owners can delete."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    if membership.role != "owner":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only organization owners can delete the organization",
        )

    await delete_organization(db, org.id)


# ── Member management ────────────────────────────────────────────


@router.get("/{org_slug}/members", response_model=MemberListResponse)
async def list_org_members(
    org_slug: str,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
    skip: int = 0,
    limit: int = 50,
) -> MemberListResponse:
    """List members of an organization."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)

    members = await list_members(db, org.id, skip=skip, limit=limit)
    total = await count_members(db, org.id)

    member_list = []
    for m in members:
        resp = MemberResponse(
            id=m.id,
            user_id=m.user_id,
            role=m.role,
            is_active=m.is_active,
            joined_at=m.joined_at,
        )
        member_list.append(resp)

    return MemberListResponse(members=member_list, total=total, skip=skip, limit=limit)


@router.post("/{org_slug}/members", response_model=MemberResponse, status_code=status.HTTP_201_CREATED)
async def add_org_member(
    org_slug: str,
    body: AddMemberRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> MemberResponse:
    """Add a member directly by user ID. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    try:
        new_membership = await add_member(db, org.id, body.user_id, role=body.role)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    return MemberResponse(
        id=new_membership.id,
        user_id=new_membership.user_id,
        role=new_membership.role,
        is_active=new_membership.is_active,
        joined_at=new_membership.joined_at,
    )


@router.patch("/{org_slug}/members/{user_id}", response_model=MemberResponse)
async def update_org_member_role(
    org_slug: str,
    user_id: int,
    body: UpdateMemberRoleRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> MemberResponse:
    """Update a member's role. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    # Prevent users from changing their own role
    if user_id == current_user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Cannot change your own role",
        )

    try:
        updated = await update_member_role(db, org.id, user_id, body.role)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    if not updated:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Member not found")

    return MemberResponse(
        id=updated.id,
        user_id=updated.user_id,
        role=updated.role,
        is_active=updated.is_active,
        joined_at=updated.joined_at,
    )


@router.delete("/{org_slug}/members/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def remove_org_member(
    org_slug: str,
    user_id: int,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Remove a member from the organization. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    try:
        removed = await remove_member(db, org.id, user_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    if not removed:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Member not found")


@router.post("/{org_slug}/leave", status_code=status.HTTP_204_NO_CONTENT)
async def leave_org(
    org_slug: str,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Leave an organization."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    try:
        removed = await remove_member(db, org.id, current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    if not removed:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not a member")


# ── Invitations ──────────────────────────────────────────────────


@router.post("/{org_slug}/invitations", response_model=InvitationResponse, status_code=status.HTTP_201_CREATED)
async def invite_to_org(
    org_slug: str,
    body: InvitationCreateRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> InvitationResponse:
    """Invite a user to the organization by email. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    try:
        invitation = await create_invitation(
            db, org.id, body.email, role=body.role, invited_by_id=current_user.id
        )
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    return InvitationResponse.model_validate(invitation)


@router.get("/{org_slug}/invitations", response_model=list[InvitationResponse])
async def list_invitations(
    org_slug: str,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> list[InvitationResponse]:
    """List pending invitations. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    invitations = await list_org_invitations(db, org.id)
    return [InvitationResponse.model_validate(inv) for inv in invitations]


@router.delete("/{org_slug}/invitations/{invitation_id}", status_code=status.HTTP_204_NO_CONTENT)
async def revoke_org_invitation(
    org_slug: str,
    invitation_id: int,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> None:
    """Revoke a pending invitation. Requires members.manage permission."""
    org = await get_organization_by_slug(db, org_slug)
    if not org or not org.is_active:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Organization not found")

    membership = await get_org_membership(db, org.id, current_user.id)
    require_org_permission(membership, "members.manage")

    if not await revoke_invitation(db, invitation_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Invitation not found")


@router.post("/invitations/accept", response_model=MemberResponse)
async def accept_org_invitation(
    body: AcceptInvitationRequest,
    current_user: CurrentActiveUser,
    db: Annotated[AsyncSession, Depends(get_db)],
) -> MemberResponse:
    """Accept an invitation to join an organization."""
    try:
        membership = await accept_invitation(db, body.token, current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    return MemberResponse(
        id=membership.id,
        user_id=membership.user_id,
        role=membership.role,
        is_active=membership.is_active,
        joined_at=membership.joined_at,
    )


# ── Roles ────────────────────────────────────────────────────────


@router.get("/roles", response_model=list[OrgRoleResponse])
async def list_org_roles(
    current_user: CurrentActiveUser,
) -> list[OrgRoleResponse]:
    """List available organization roles and their permissions."""
    return [
{% for role in org_roles %}
        OrgRoleResponse(
            name="{{ role.name }}",
            permissions={{ role.permissions }},
            description="{{ role.description }}",
        ),
{% endfor %}
    ]
