"""
BYOEH Invitation Flow Routes

Endpoints for inviting users, listing/accepting/declining/revoking
invitations to access Erwartungshorizonte.
Extracted from routes/eh.py for file-size compliance.
"""

import uuid
from datetime import datetime, timezone, timedelta

from fastapi import APIRouter, HTTPException, Request

from models.eh import EHKeyShare, EHShareInvitation
from models.requests import EHInviteRequest, EHAcceptInviteRequest
from services.auth_service import get_current_user
from services.eh_service import log_eh_audit
import storage

router = APIRouter()


# =============================================
# INVITATION FLOW
# =============================================

@router.post("/api/v1/eh/{eh_id}/invite")
async def invite_to_eh(
    eh_id: str,
    invite_request: EHInviteRequest,
    request: Request
):
    """
    Invite another user to access an Erwartungshorizont.

    This creates a pending invitation that the recipient must accept.
    """
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    # Check EH exists and belongs to user
    if eh_id not in storage.eh_db:
        raise HTTPException(status_code=404, detail="Erwartungshorizont not found")

    eh = storage.eh_db[eh_id]
    if eh.teacher_id != user["user_id"]:
        raise HTTPException(status_code=403, detail="Only the owner can invite others")

    # Validate role
    valid_roles = ['second_examiner', 'third_examiner', 'supervisor', 'department_head', 'fachvorsitz']
    if invite_request.role not in valid_roles:
        raise HTTPException(status_code=400, detail=f"Invalid role. Must be one of: {valid_roles}")

    # Check for existing pending invitation to same user
    for inv in storage.eh_invitations_db.values():
        if (inv.eh_id == eh_id and
            inv.invitee_email == invite_request.invitee_email and
            inv.status == 'pending'):
            raise HTTPException(
                status_code=409,
                detail="Pending invitation already exists for this user"
            )

    # Create invitation
    invitation_id = str(uuid.uuid4())
    now = datetime.now(timezone.utc)
    expires_at = now + timedelta(days=invite_request.expires_in_days)

    invitation = EHShareInvitation(
        id=invitation_id,
        eh_id=eh_id,
        inviter_id=user["user_id"],
        invitee_id=invite_request.invitee_id or "",
        invitee_email=invite_request.invitee_email,
        role=invite_request.role,
        klausur_id=invite_request.klausur_id,
        message=invite_request.message,
        status='pending',
        expires_at=expires_at,
        created_at=now,
        accepted_at=None,
        declined_at=None
    )

    storage.eh_invitations_db[invitation_id] = invitation

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user["user_id"],
        action="invite",
        eh_id=eh_id,
        details={
            "invitation_id": invitation_id,
            "invitee_email": invite_request.invitee_email,
            "role": invite_request.role,
            "expires_at": expires_at.isoformat()
        }
    )

    return {
        "status": "invited",
        "invitation_id": invitation_id,
        "eh_id": eh_id,
        "invitee_email": invite_request.invitee_email,
        "role": invite_request.role,
        "expires_at": expires_at.isoformat(),
        "eh_title": eh.title
    }


@router.get("/api/v1/eh/invitations/pending")
async def list_pending_invitations(request: Request):
    """List all pending invitations for the current user."""
    user = get_current_user(request)
    user_email = user.get("email", "")
    user_id = user["user_id"]
    now = datetime.now(timezone.utc)

    pending = []
    for inv in storage.eh_invitations_db.values():
        # Match by email or user_id
        if (inv.invitee_email == user_email or inv.invitee_id == user_id):
            if inv.status == 'pending' and inv.expires_at > now:
                # Get EH info
                eh_info = None
                if inv.eh_id in storage.eh_db:
                    eh = storage.eh_db[inv.eh_id]
                    eh_info = {
                        "id": eh.id,
                        "title": eh.title,
                        "subject": eh.subject,
                        "niveau": eh.niveau,
                        "year": eh.year
                    }

                pending.append({
                    "invitation": inv.to_dict(),
                    "eh": eh_info
                })

    return pending


@router.get("/api/v1/eh/invitations/sent")
async def list_sent_invitations(request: Request):
    """List all invitations sent by the current user."""
    user = get_current_user(request)
    user_id = user["user_id"]

    sent = []
    for inv in storage.eh_invitations_db.values():
        if inv.inviter_id == user_id:
            # Get EH info
            eh_info = None
            if inv.eh_id in storage.eh_db:
                eh = storage.eh_db[inv.eh_id]
                eh_info = {
                    "id": eh.id,
                    "title": eh.title,
                    "subject": eh.subject
                }

            sent.append({
                "invitation": inv.to_dict(),
                "eh": eh_info
            })

    return sent


@router.post("/api/v1/eh/invitations/{invitation_id}/accept")
async def accept_eh_invitation(
    invitation_id: str,
    accept_request: EHAcceptInviteRequest,
    request: Request
):
    """Accept an invitation and receive access to the EH."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]
    user_email = user.get("email", "")
    user_id = user["user_id"]
    now = datetime.now(timezone.utc)

    # Find invitation
    if invitation_id not in storage.eh_invitations_db:
        raise HTTPException(status_code=404, detail="Invitation not found")

    invitation = storage.eh_invitations_db[invitation_id]

    # Verify recipient
    if invitation.invitee_email != user_email and invitation.invitee_id != user_id:
        raise HTTPException(status_code=403, detail="This invitation is not for you")

    # Check status
    if invitation.status != 'pending':
        raise HTTPException(
            status_code=400,
            detail=f"Invitation is {invitation.status}, cannot accept"
        )

    # Check expiration
    if invitation.expires_at < now:
        invitation.status = 'expired'
        raise HTTPException(status_code=400, detail="Invitation has expired")

    # Create key share
    share_id = str(uuid.uuid4())
    key_share = EHKeyShare(
        id=share_id,
        eh_id=invitation.eh_id,
        user_id=user_id,
        encrypted_passphrase=accept_request.encrypted_passphrase,
        passphrase_hint="",
        granted_by=invitation.inviter_id,
        granted_at=now,
        role=invitation.role,
        klausur_id=invitation.klausur_id,
        active=True
    )

    # Store key share
    if invitation.eh_id not in storage.eh_key_shares_db:
        storage.eh_key_shares_db[invitation.eh_id] = []
    storage.eh_key_shares_db[invitation.eh_id].append(key_share)

    # Update invitation status
    invitation.status = 'accepted'
    invitation.accepted_at = now
    invitation.invitee_id = user_id  # Update with actual user ID

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user_id,
        action="accept_invite",
        eh_id=invitation.eh_id,
        details={
            "invitation_id": invitation_id,
            "share_id": share_id,
            "role": invitation.role
        }
    )

    return {
        "status": "accepted",
        "share_id": share_id,
        "eh_id": invitation.eh_id,
        "role": invitation.role,
        "klausur_id": invitation.klausur_id
    }


@router.post("/api/v1/eh/invitations/{invitation_id}/decline")
async def decline_eh_invitation(invitation_id: str, request: Request):
    """Decline an invitation."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]
    user_email = user.get("email", "")
    user_id = user["user_id"]
    now = datetime.now(timezone.utc)

    # Find invitation
    if invitation_id not in storage.eh_invitations_db:
        raise HTTPException(status_code=404, detail="Invitation not found")

    invitation = storage.eh_invitations_db[invitation_id]

    # Verify recipient
    if invitation.invitee_email != user_email and invitation.invitee_id != user_id:
        raise HTTPException(status_code=403, detail="This invitation is not for you")

    # Check status
    if invitation.status != 'pending':
        raise HTTPException(
            status_code=400,
            detail=f"Invitation is {invitation.status}, cannot decline"
        )

    # Update status
    invitation.status = 'declined'
    invitation.declined_at = now

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user_id,
        action="decline_invite",
        eh_id=invitation.eh_id,
        details={"invitation_id": invitation_id}
    )

    return {
        "status": "declined",
        "invitation_id": invitation_id,
        "eh_id": invitation.eh_id
    }


@router.delete("/api/v1/eh/invitations/{invitation_id}")
async def revoke_eh_invitation(invitation_id: str, request: Request):
    """Revoke a pending invitation (by the inviter)."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]
    user_id = user["user_id"]

    # Find invitation
    if invitation_id not in storage.eh_invitations_db:
        raise HTTPException(status_code=404, detail="Invitation not found")

    invitation = storage.eh_invitations_db[invitation_id]

    # Verify inviter
    if invitation.inviter_id != user_id:
        raise HTTPException(status_code=403, detail="Only the inviter can revoke")

    # Check status
    if invitation.status != 'pending':
        raise HTTPException(
            status_code=400,
            detail=f"Invitation is {invitation.status}, cannot revoke"
        )

    # Update status
    invitation.status = 'revoked'

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user_id,
        action="revoke_invite",
        eh_id=invitation.eh_id,
        details={
            "invitation_id": invitation_id,
            "invitee_email": invitation.invitee_email
        }
    )

    return {
        "status": "revoked",
        "invitation_id": invitation_id,
        "eh_id": invitation.eh_id
    }
