"""
Klausur-Service BYOEH Routes

Endpoints for Bring-Your-Own-Expectation-Horizon (BYOEH).
"""

import os
import uuid
import json
from datetime import datetime, timezone, timedelta
from typing import Optional

from fastapi import APIRouter, HTTPException, Request, UploadFile, File, Form, BackgroundTasks

from models.enums import EHStatus
from models.eh import (
    Erwartungshorizont,
    EHRightsConfirmation,
    EHKeyShare,
    EHKlausurLink,
    EHShareInvitation,
)
from models.requests import (
    EHMetadata,
    EHUploadMetadata,
    EHRAGQuery,
    EHIndexRequest,
    EHShareRequest,
    EHLinkKlausurRequest,
    EHInviteRequest,
    EHAcceptInviteRequest,
)
from services.auth_service import get_current_user
from services.eh_service import log_eh_audit
from config import EH_UPLOAD_DIR, OPENAI_API_KEY, ENVIRONMENT, RIGHTS_CONFIRMATION_TEXT
import storage

# BYOEH imports
from qdrant_service import (
    get_collection_info, delete_eh_vectors, search_eh, index_eh_chunks
)
from eh_pipeline import (
    decrypt_text, verify_key_hash, process_eh_for_indexing,
    generate_single_embedding, EncryptionError, EmbeddingError
)

router = APIRouter()


# =============================================
# EH UPLOAD & LIST
# =============================================

@router.post("/api/v1/eh/upload")
async def upload_erwartungshorizont(
    file: UploadFile = File(...),
    metadata_json: str = Form(...),
    request: Request = None,
    background_tasks: BackgroundTasks = None
):
    """
    Upload an encrypted Erwartungshorizont.

    The file MUST be client-side encrypted.
    Server stores only the encrypted blob + key hash (never the passphrase).
    """
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    try:
        data = EHUploadMetadata(**json.loads(metadata_json))
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Invalid metadata: {str(e)}")

    if not data.rights_confirmed:
        raise HTTPException(status_code=400, detail="Rights confirmation required")

    eh_id = str(uuid.uuid4())

    # Create tenant-isolated directory
    upload_dir = f"{EH_UPLOAD_DIR}/{tenant_id}/{eh_id}"
    os.makedirs(upload_dir, exist_ok=True)

    # Save encrypted file
    encrypted_path = f"{upload_dir}/encrypted.bin"
    content = await file.read()
    with open(encrypted_path, "wb") as f:
        f.write(content)

    # Save salt separately
    with open(f"{upload_dir}/salt.txt", "w") as f:
        f.write(data.salt)

    # Create EH record
    eh = Erwartungshorizont(
        id=eh_id,
        tenant_id=tenant_id,
        teacher_id=user["user_id"],
        title=data.metadata.title,
        subject=data.metadata.subject,
        niveau=data.metadata.niveau,
        year=data.metadata.year,
        aufgaben_nummer=data.metadata.aufgaben_nummer,
        encryption_key_hash=data.encryption_key_hash,
        salt=data.salt,
        encrypted_file_path=encrypted_path,
        file_size_bytes=len(content),
        original_filename=data.original_filename,
        rights_confirmed=True,
        rights_confirmed_at=datetime.now(timezone.utc),
        status=EHStatus.PENDING_RIGHTS,
        chunk_count=0,
        indexed_at=None,
        error_message=None,
        training_allowed=False,  # ALWAYS FALSE - critical for compliance
        created_at=datetime.now(timezone.utc),
        deleted_at=None
    )

    storage.eh_db[eh_id] = eh

    # Store rights confirmation
    rights_confirmation = EHRightsConfirmation(
        id=str(uuid.uuid4()),
        eh_id=eh_id,
        teacher_id=user["user_id"],
        confirmation_type="upload",
        confirmation_text=RIGHTS_CONFIRMATION_TEXT,
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent"),
        confirmed_at=datetime.now(timezone.utc)
    )
    storage.eh_rights_db[rights_confirmation.id] = rights_confirmation

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user["user_id"],
        action="upload",
        eh_id=eh_id,
        details={
            "subject": data.metadata.subject,
            "year": data.metadata.year,
            "file_size": len(content)
        },
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent")
    )

    return eh.to_dict()


@router.get("/api/v1/eh")
async def list_erwartungshorizonte(
    request: Request,
    subject: Optional[str] = None,
    year: Optional[int] = None
):
    """List all Erwartungshorizonte for the current teacher."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    results = []
    for eh in storage.eh_db.values():
        if eh.tenant_id == tenant_id and eh.deleted_at is None:
            if subject and eh.subject != subject:
                continue
            if year and eh.year != year:
                continue
            results.append(eh.to_dict())

    return results


# =============================================
# SPECIFIC EH ROUTES (must come before {eh_id} catch-all)
# =============================================

@router.get("/api/v1/eh/audit-log")
async def get_eh_audit_log(
    request: Request,
    eh_id: Optional[str] = None,
    limit: int = 100
):
    """Get BYOEH audit log entries."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    # Filter by tenant
    entries = [e for e in storage.eh_audit_db if e.tenant_id == tenant_id]

    # Filter by EH if specified
    if eh_id:
        entries = [e for e in entries if e.eh_id == eh_id]

    # Sort and limit
    entries = sorted(entries, key=lambda e: e.created_at, reverse=True)[:limit]

    return [e.to_dict() for e in entries]


@router.get("/api/v1/eh/rights-text")
async def get_rights_confirmation_text():
    """Get the rights confirmation text for display in UI."""
    return {
        "text": RIGHTS_CONFIRMATION_TEXT,
        "version": "v1.0"
    }


@router.get("/api/v1/eh/qdrant-status")
async def get_qdrant_status(request: Request):
    """Get Qdrant collection status (admin only)."""
    user = get_current_user(request)
    if user.get("role") != "admin" and ENVIRONMENT != "development":
        raise HTTPException(status_code=403, detail="Admin access required")

    return await get_collection_info()


@router.get("/api/v1/eh/shared-with-me")
async def list_shared_eh(request: Request):
    """List all EH shared with the current user."""
    user = get_current_user(request)
    user_id = user["user_id"]

    shared_ehs = []
    for eh_id, shares in storage.eh_key_shares_db.items():
        for share in shares:
            if share.user_id == user_id and share.active:
                if eh_id in storage.eh_db:
                    eh = storage.eh_db[eh_id]
                    shared_ehs.append({
                        "eh": eh.to_dict(),
                        "share": share.to_dict()
                    })

    return shared_ehs


# =============================================
# GENERIC EH ROUTES
# =============================================

@router.get("/api/v1/eh/{eh_id}")
async def get_erwartungshorizont(eh_id: str, request: Request):
    """Get a specific Erwartungshorizont by ID."""
    user = get_current_user(request)

    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"] and user.get("role") != "admin":
        raise HTTPException(status_code=403, detail="Access denied")

    if eh.deleted_at is not None:
        raise HTTPException(status_code=404, detail="Erwartungshorizont was deleted")

    return eh.to_dict()


@router.delete("/api/v1/eh/{eh_id}")
async def delete_erwartungshorizont(eh_id: str, request: Request):
    """Soft-delete an Erwartungshorizont and remove vectors from Qdrant."""
    user = get_current_user(request)

    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"] and user.get("role") != "admin":
        raise HTTPException(status_code=403, detail="Access denied")

    # Soft delete
    eh.deleted_at = datetime.now(timezone.utc)

    # Delete vectors from Qdrant
    try:
        deleted_count = await delete_eh_vectors(eh_id)
        print(f"Deleted {deleted_count} vectors for EH {eh_id}")
    except Exception as e:
        print(f"Warning: Failed to delete vectors: {e}")

    # Audit log
    log_eh_audit(
        tenant_id=eh.tenant_id,
        user_id=user["user_id"],
        action="delete",
        eh_id=eh_id,
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent")
    )

    return {"status": "deleted", "id": eh_id}


@router.post("/api/v1/eh/{eh_id}/index")
async def index_erwartungshorizont(
    eh_id: str,
    data: EHIndexRequest,
    request: Request
):
    """
    Index an Erwartungshorizont for RAG queries.

    Requires the passphrase to decrypt, chunk, embed, and re-encrypt chunks.
    The passphrase is only used transiently and never stored.
    """
    user = get_current_user(request)

    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"] and user.get("role") != "admin":
        raise HTTPException(status_code=403, detail="Access denied")

    # Verify passphrase matches key hash
    if not verify_key_hash(data.passphrase, eh.salt, eh.encryption_key_hash):
        raise HTTPException(status_code=401, detail="Invalid passphrase")

    eh.status = EHStatus.PROCESSING

    try:
        # Read encrypted file
        with open(eh.encrypted_file_path, "rb") as f:
            encrypted_content = f.read()

        # Decrypt the file
        decrypted_text = decrypt_text(
            encrypted_content.decode('utf-8'),
            data.passphrase,
            eh.salt
        )

        # Process for indexing
        chunk_count, chunks_data = await process_eh_for_indexing(
            eh_id=eh_id,
            tenant_id=eh.tenant_id,
            subject=eh.subject,
            text_content=decrypted_text,
            passphrase=data.passphrase,
            salt_hex=eh.salt
        )

        # Index in Qdrant
        await index_eh_chunks(
            eh_id=eh_id,
            tenant_id=eh.tenant_id,
            subject=eh.subject,
            chunks=chunks_data
        )

        # Update EH record
        eh.status = EHStatus.INDEXED
        eh.chunk_count = chunk_count
        eh.indexed_at = datetime.now(timezone.utc)

        # Audit log
        log_eh_audit(
            tenant_id=eh.tenant_id,
            user_id=user["user_id"],
            action="indexed",
            eh_id=eh_id,
            details={"chunk_count": chunk_count}
        )

        return {
            "status": "indexed",
            "id": eh_id,
            "chunk_count": chunk_count
        }

    except EncryptionError as e:
        eh.status = EHStatus.ERROR
        eh.error_message = str(e)
        raise HTTPException(status_code=400, detail=f"Decryption failed: {str(e)}")
    except EmbeddingError as e:
        eh.status = EHStatus.ERROR
        eh.error_message = str(e)
        raise HTTPException(status_code=500, detail=f"Embedding generation failed: {str(e)}")
    except Exception as e:
        eh.status = EHStatus.ERROR
        eh.error_message = str(e)
        raise HTTPException(status_code=500, detail=f"Indexing failed: {str(e)}")


@router.post("/api/v1/eh/rag-query")
async def rag_query_eh(data: EHRAGQuery, request: Request):
    """
    RAG query against teacher's Erwartungshorizonte.

    1. Semantic search in Qdrant (tenant-isolated)
    2. Decrypt relevant chunks on-the-fly
    3. Return context for LLM usage
    """
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    if not OPENAI_API_KEY:
        raise HTTPException(status_code=500, detail="OpenAI API key not configured")

    try:
        # Generate embedding for query
        query_embedding = await generate_single_embedding(data.query_text)

        # Search in Qdrant (tenant-isolated)
        results = await search_eh(
            query_embedding=query_embedding,
            tenant_id=tenant_id,
            subject=data.subject,
            limit=data.limit
        )

        # Decrypt matching chunks
        decrypted_chunks = []
        for r in results:
            eh = storage.eh_db.get(r["eh_id"])
            if eh and r.get("encrypted_content"):
                try:
                    decrypted = decrypt_text(
                        r["encrypted_content"],
                        data.passphrase,
                        eh.salt
                    )
                    decrypted_chunks.append({
                        "text": decrypted,
                        "eh_id": r["eh_id"],
                        "eh_title": eh.title,
                        "chunk_index": r["chunk_index"],
                        "score": r["score"]
                    })
                except EncryptionError:
                    # Skip chunks that can't be decrypted (wrong passphrase for different EH)
                    pass

        # Audit log
        log_eh_audit(
            tenant_id=tenant_id,
            user_id=user["user_id"],
            action="rag_query",
            details={
                "query_length": len(data.query_text),
                "results_count": len(results),
                "decrypted_count": len(decrypted_chunks)
            },
            ip_address=request.client.host if request.client else None,
            user_agent=request.headers.get("user-agent")
        )

        return {
            "context": "\n\n---\n\n".join([c["text"] for c in decrypted_chunks]),
            "sources": decrypted_chunks,
            "query": data.query_text
        }

    except EmbeddingError as e:
        raise HTTPException(status_code=500, detail=f"Query embedding failed: {str(e)}")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"RAG query failed: {str(e)}")


# =============================================
# BYOEH KEY SHARING
# =============================================

@router.post("/api/v1/eh/{eh_id}/share")
async def share_erwartungshorizont(
    eh_id: str,
    share_request: EHShareRequest,
    request: Request
):
    """
    Share an Erwartungshorizont with another examiner.

    The first examiner shares their EH by providing an encrypted passphrase
    that the recipient can use.
    """
    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 share this EH")

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

    # Create key share entry
    share_id = str(uuid.uuid4())
    key_share = EHKeyShare(
        id=share_id,
        eh_id=eh_id,
        user_id=share_request.user_id,
        encrypted_passphrase=share_request.encrypted_passphrase,
        passphrase_hint=share_request.passphrase_hint or "",
        granted_by=user["user_id"],
        granted_at=datetime.now(timezone.utc),
        role=share_request.role,
        klausur_id=share_request.klausur_id,
        active=True
    )

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

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user["user_id"],
        action="share",
        eh_id=eh_id,
        details={
            "shared_with": share_request.user_id,
            "role": share_request.role,
            "klausur_id": share_request.klausur_id
        }
    )

    return {
        "status": "shared",
        "share_id": share_id,
        "eh_id": eh_id,
        "shared_with": share_request.user_id,
        "role": share_request.role
    }


@router.get("/api/v1/eh/{eh_id}/shares")
async def list_eh_shares(eh_id: str, request: Request):
    """List all users who have access to an EH."""
    user = get_current_user(request)

    # 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 view shares")

    shares = storage.eh_key_shares_db.get(eh_id, [])
    return [share.to_dict() for share in shares if share.active]


@router.delete("/api/v1/eh/{eh_id}/shares/{share_id}")
async def revoke_eh_share(eh_id: str, share_id: str, request: Request):
    """Revoke a shared EH access."""
    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 revoke shares")

    # Find and deactivate share
    shares = storage.eh_key_shares_db.get(eh_id, [])
    for share in shares:
        if share.id == share_id:
            share.active = False

            log_eh_audit(
                tenant_id=tenant_id,
                user_id=user["user_id"],
                action="revoke_share",
                eh_id=eh_id,
                details={"revoked_user": share.user_id, "share_id": share_id}
            )

            return {"status": "revoked", "share_id": share_id}

    raise HTTPException(status_code=404, detail="Share not found")


# =============================================
# KLAUSUR LINKING
# =============================================

@router.post("/api/v1/eh/{eh_id}/link-klausur")
async def link_eh_to_klausur(
    eh_id: str,
    link_request: EHLinkKlausurRequest,
    request: Request
):
    """
    Link an Erwartungshorizont to a Klausur.

    This creates an association between the EH and a specific Klausur.
    """
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

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

    eh = storage.eh_db[eh_id]
    user_has_access = (
        eh.teacher_id == user["user_id"] or
        any(
            share.user_id == user["user_id"] and share.active
            for share in storage.eh_key_shares_db.get(eh_id, [])
        )
    )

    if not user_has_access:
        raise HTTPException(status_code=403, detail="No access to this EH")

    # Check Klausur exists
    klausur_id = link_request.klausur_id
    if klausur_id not in storage.klausuren_db:
        raise HTTPException(status_code=404, detail="Klausur not found")

    # Create link
    link_id = str(uuid.uuid4())
    link = EHKlausurLink(
        id=link_id,
        eh_id=eh_id,
        klausur_id=klausur_id,
        linked_by=user["user_id"],
        linked_at=datetime.now(timezone.utc)
    )

    if klausur_id not in storage.eh_klausur_links_db:
        storage.eh_klausur_links_db[klausur_id] = []
    storage.eh_klausur_links_db[klausur_id].append(link)

    # Audit log
    log_eh_audit(
        tenant_id=tenant_id,
        user_id=user["user_id"],
        action="link_klausur",
        eh_id=eh_id,
        details={"klausur_id": klausur_id}
    )

    return {
        "status": "linked",
        "link_id": link_id,
        "eh_id": eh_id,
        "klausur_id": klausur_id
    }


@router.get("/api/v1/klausuren/{klausur_id}/linked-eh")
async def get_linked_eh(klausur_id: str, request: Request):
    """Get all EH linked to a specific Klausur."""
    user = get_current_user(request)
    user_id = user["user_id"]

    # Check Klausur exists
    if klausur_id not in storage.klausuren_db:
        raise HTTPException(status_code=404, detail="Klausur not found")

    # Get all links for this Klausur
    links = storage.eh_klausur_links_db.get(klausur_id, [])

    linked_ehs = []
    for link in links:
        if link.eh_id in storage.eh_db:
            eh = storage.eh_db[link.eh_id]

            # Check if user has access to this EH
            is_owner = eh.teacher_id == user_id
            is_shared = any(
                share.user_id == user_id and share.active
                for share in storage.eh_key_shares_db.get(link.eh_id, [])
            )

            if is_owner or is_shared:
                # Find user's share info if shared
                share_info = None
                if is_shared:
                    for share in storage.eh_key_shares_db.get(link.eh_id, []):
                        if share.user_id == user_id and share.active:
                            share_info = share.to_dict()
                            break

                linked_ehs.append({
                    "eh": eh.to_dict(),
                    "link": link.to_dict(),
                    "is_owner": is_owner,
                    "share": share_info
                })

    return linked_ehs


@router.delete("/api/v1/eh/{eh_id}/link-klausur/{klausur_id}")
async def unlink_eh_from_klausur(eh_id: str, klausur_id: str, request: Request):
    """Remove the link between an EH and a Klausur."""
    user = get_current_user(request)
    tenant_id = user.get("tenant_id") or user.get("school_id") or user["user_id"]

    # Check EH exists and user has access
    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 unlink")

    # Find and remove link
    links = storage.eh_klausur_links_db.get(klausur_id, [])
    for i, link in enumerate(links):
        if link.eh_id == eh_id:
            del links[i]

            log_eh_audit(
                tenant_id=tenant_id,
                user_id=user["user_id"],
                action="unlink_klausur",
                eh_id=eh_id,
                details={"klausur_id": klausur_id}
            )

            return {"status": "unlinked", "eh_id": eh_id, "klausur_id": klausur_id}

    raise HTTPException(status_code=404, detail="Link not found")


# =============================================
# 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
    }


@router.get("/api/v1/eh/{eh_id}/access-chain")
async def get_eh_access_chain(eh_id: str, request: Request):
    """
    Get the complete access chain for an EH.

    Shows the correction chain: EK -> ZK -> DK -> FVL
    with their current access status.
    """
    user = get_current_user(request)

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

    eh = storage.eh_db[eh_id]

    # Check access - owner or shared user
    is_owner = eh.teacher_id == user["user_id"]
    is_shared = any(
        share.user_id == user["user_id"] and share.active
        for share in storage.eh_key_shares_db.get(eh_id, [])
    )

    if not is_owner and not is_shared:
        raise HTTPException(status_code=403, detail="No access to this EH")

    # Build access chain
    chain = {
        "eh_id": eh_id,
        "eh_title": eh.title,
        "owner": {
            "user_id": eh.teacher_id,
            "role": "erstkorrektor"
        },
        "active_shares": [],
        "pending_invitations": [],
        "revoked_shares": []
    }

    # Active shares
    for share in storage.eh_key_shares_db.get(eh_id, []):
        share_dict = share.to_dict()
        if share.active:
            chain["active_shares"].append(share_dict)
        else:
            chain["revoked_shares"].append(share_dict)

    # Pending invitations (only for owner)
    if is_owner:
        for inv in storage.eh_invitations_db.values():
            if inv.eh_id == eh_id and inv.status == 'pending':
                chain["pending_invitations"].append(inv.to_dict())

    return chain
