"""
RBAC Teachers API - Teacher Management Endpoints

Provides API endpoints for:
- Listing all teachers with roles
- Getting teacher roles
- Getting teachers by role
- Creating, updating, deactivating teachers

Split from rbac_api.py for file-size compliance.
"""

import uuid
from datetime import datetime, timezone
from typing import Dict, Any, List
from fastapi import APIRouter, HTTPException, Depends

from rbac_api import (
    get_pool,
    get_current_user,
    TeacherCreate,
    TeacherUpdate,
    TeacherResponse,
    RoleAssignmentResponse,
    AVAILABLE_ROLES,
)

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


def _build_teacher_response(teacher_row, roles: List[str]) -> TeacherResponse:
    """Build a TeacherResponse from a DB row and a list of role strings."""
    return TeacherResponse(
        id=str(teacher_row["id"]),
        user_id=str(teacher_row["user_id"]),
        email=teacher_row["email"],
        name=teacher_row["name"] or f"{teacher_row['first_name']} {teacher_row['last_name']}",
        teacher_code=teacher_row["teacher_code"],
        title=teacher_row["title"],
        first_name=teacher_row["first_name"],
        last_name=teacher_row["last_name"],
        is_active=teacher_row["is_active"],
        roles=roles,
    )


def _build_role_lookup(role_assignments) -> Dict[str, List[str]]:
    """Build a user_id -> [roles] lookup from role assignment rows."""
    role_lookup: Dict[str, List[str]] = {}
    for ra in role_assignments:
        uid = str(ra["user_id"])
        if uid not in role_lookup:
            role_lookup[uid] = []
        role_lookup[uid].append(ra["role"])
    return role_lookup


# ==========================================
# TEACHER LISTING / QUERY ENDPOINTS
# ==========================================


@router.get("/teachers")
async def list_teachers(
    user: Dict[str, Any] = Depends(get_current_user),
) -> List[TeacherResponse]:
    """List all teachers with their current roles"""
    pool = await get_pool()

    async with pool.acquire() as conn:
        teachers = await conn.fetch("""
            SELECT
                t.id, t.user_id, t.teacher_code, t.title,
                t.first_name, t.last_name, t.is_active,
                u.email, u.name
            FROM teachers t
            JOIN users u ON t.user_id = u.id
            WHERE t.school_id = 'a0000000-0000-0000-0000-000000000001'
            ORDER BY t.last_name, t.first_name
        """)

        role_assignments = await conn.fetch("""
            SELECT user_id, role
            FROM role_assignments
            WHERE tenant_id = 'a0000000-0000-0000-0000-000000000001'
              AND revoked_at IS NULL
              AND (valid_to IS NULL OR valid_to > NOW())
        """)

        role_lookup = _build_role_lookup(role_assignments)

        return [
            _build_teacher_response(t, role_lookup.get(str(t["user_id"]), []))
            for t in teachers
        ]


@router.get("/teachers/{teacher_id}/roles")
async def get_teacher_roles(
    teacher_id: str,
    user: Dict[str, Any] = Depends(get_current_user),
) -> List[RoleAssignmentResponse]:
    """Get all role assignments for a specific teacher"""
    pool = await get_pool()

    async with pool.acquire() as conn:
        teacher = await conn.fetchrow(
            "SELECT user_id FROM teachers WHERE id = $1",
            teacher_id,
        )
        if not teacher:
            raise HTTPException(status_code=404, detail="Teacher not found")

        assignments = await conn.fetch("""
            SELECT id, user_id, role, resource_type, resource_id,
                   valid_from, valid_to, granted_at, revoked_at
            FROM role_assignments
            WHERE user_id = $1
            ORDER BY granted_at DESC
        """, teacher["user_id"])

        return [
            RoleAssignmentResponse(
                id=str(a["id"]),
                user_id=str(a["user_id"]),
                role=a["role"],
                resource_type=a["resource_type"],
                resource_id=str(a["resource_id"]),
                valid_from=a["valid_from"].isoformat() if a["valid_from"] else None,
                valid_to=a["valid_to"].isoformat() if a["valid_to"] else None,
                granted_at=a["granted_at"].isoformat() if a["granted_at"] else None,
                is_active=a["revoked_at"] is None and (
                    a["valid_to"] is None or a["valid_to"] > datetime.now(timezone.utc)
                ),
            )
            for a in assignments
        ]


@router.get("/roles/{role}/teachers")
async def get_teachers_by_role(
    role: str,
    user: Dict[str, Any] = Depends(get_current_user),
) -> List[TeacherResponse]:
    """Get all teachers with a specific role"""
    if role not in AVAILABLE_ROLES:
        raise HTTPException(status_code=400, detail=f"Unknown role: {role}")

    pool = await get_pool()

    async with pool.acquire() as conn:
        teachers = await conn.fetch("""
            SELECT DISTINCT
                t.id, t.user_id, t.teacher_code, t.title,
                t.first_name, t.last_name, t.is_active,
                u.email, u.name
            FROM teachers t
            JOIN users u ON t.user_id = u.id
            JOIN role_assignments ra ON t.user_id = ra.user_id
            WHERE ra.role = $1
              AND ra.revoked_at IS NULL
              AND (ra.valid_to IS NULL OR ra.valid_to > NOW())
              AND t.school_id = 'a0000000-0000-0000-0000-000000000001'
            ORDER BY t.last_name, t.first_name
        """, role)

        if teachers:
            user_ids = [t["user_id"] for t in teachers]
            role_assignments = await conn.fetch("""
                SELECT user_id, role
                FROM role_assignments
                WHERE user_id = ANY($1)
                  AND revoked_at IS NULL
                  AND (valid_to IS NULL OR valid_to > NOW())
            """, user_ids)
            role_lookup = _build_role_lookup(role_assignments)
        else:
            role_lookup = {}

        return [
            _build_teacher_response(t, role_lookup.get(str(t["user_id"]), []))
            for t in teachers
        ]


# ==========================================
# TEACHER CRUD ENDPOINTS
# ==========================================


@router.post("/teachers")
async def create_teacher(
    teacher: TeacherCreate,
    user: Dict[str, Any] = Depends(get_current_user),
) -> TeacherResponse:
    """Create a new teacher with optional initial roles"""
    pool = await get_pool()

    async with pool.acquire() as conn:
        existing = await conn.fetchrow(
            "SELECT id FROM users WHERE email = $1",
            teacher.email,
        )
        if existing:
            raise HTTPException(status_code=409, detail="Email already exists")

        user_id = str(uuid.uuid4())
        teacher_id = str(uuid.uuid4())

        await conn.execute("""
            INSERT INTO users (id, email, name, password_hash, role, is_active)
            VALUES ($1, $2, $3, '', 'teacher', true)
        """, user_id, teacher.email, f"{teacher.first_name} {teacher.last_name}")

        await conn.execute("""
            INSERT INTO teachers (id, user_id, school_id, first_name, last_name, teacher_code, title, is_active)
            VALUES ($1, $2, 'a0000000-0000-0000-0000-000000000001', $3, $4, $5, $6, true)
        """, teacher_id, user_id, teacher.first_name, teacher.last_name,
            teacher.teacher_code, teacher.title)

        assigned_roles = []
        for role in teacher.roles:
            if role in AVAILABLE_ROLES or await conn.fetchrow(
                "SELECT 1 FROM custom_roles WHERE role_key = $1 AND is_active = true", role
            ):
                await conn.execute("""
                    INSERT INTO role_assignments (user_id, role, resource_type, resource_id, tenant_id, granted_by)
                    VALUES ($1, $2, 'tenant', 'a0000000-0000-0000-0000-000000000001',
                            'a0000000-0000-0000-0000-000000000001', $3)
                """, user_id, role, user.get("user_id"))
                assigned_roles.append(role)

        return TeacherResponse(
            id=teacher_id,
            user_id=user_id,
            email=teacher.email,
            name=f"{teacher.first_name} {teacher.last_name}",
            teacher_code=teacher.teacher_code,
            title=teacher.title,
            first_name=teacher.first_name,
            last_name=teacher.last_name,
            is_active=True,
            roles=assigned_roles,
        )


@router.put("/teachers/{teacher_id}")
async def update_teacher(
    teacher_id: str,
    updates: TeacherUpdate,
    user: Dict[str, Any] = Depends(get_current_user),
) -> TeacherResponse:
    """Update teacher information"""
    pool = await get_pool()

    async with pool.acquire() as conn:
        teacher = await conn.fetchrow("""
            SELECT t.id, t.user_id, t.teacher_code, t.title, t.first_name, t.last_name, t.is_active,
                   u.email, u.name
            FROM teachers t
            JOIN users u ON t.user_id = u.id
            WHERE t.id = $1
        """, teacher_id)

        if not teacher:
            raise HTTPException(status_code=404, detail="Teacher not found")

        if updates.email:
            await conn.execute(
                "UPDATE users SET email = $1 WHERE id = $2",
                updates.email, teacher["user_id"],
            )

        teacher_updates = []
        teacher_values = []
        idx = 1

        if updates.first_name:
            teacher_updates.append(f"first_name = ${idx}")
            teacher_values.append(updates.first_name)
            idx += 1
        if updates.last_name:
            teacher_updates.append(f"last_name = ${idx}")
            teacher_values.append(updates.last_name)
            idx += 1
        if updates.teacher_code is not None:
            teacher_updates.append(f"teacher_code = ${idx}")
            teacher_values.append(updates.teacher_code)
            idx += 1
        if updates.title is not None:
            teacher_updates.append(f"title = ${idx}")
            teacher_values.append(updates.title)
            idx += 1
        if updates.is_active is not None:
            teacher_updates.append(f"is_active = ${idx}")
            teacher_values.append(updates.is_active)
            idx += 1

        if teacher_updates:
            teacher_values.append(teacher_id)
            await conn.execute(
                f"UPDATE teachers SET {', '.join(teacher_updates)} WHERE id = ${idx}",
                *teacher_values,
            )

        if updates.first_name or updates.last_name:
            new_first = updates.first_name or teacher["first_name"]
            new_last = updates.last_name or teacher["last_name"]
            await conn.execute(
                "UPDATE users SET name = $1 WHERE id = $2",
                f"{new_first} {new_last}", teacher["user_id"],
            )

        updated = await conn.fetchrow("""
            SELECT t.id, t.user_id, t.teacher_code, t.title, t.first_name, t.last_name, t.is_active,
                   u.email, u.name
            FROM teachers t
            JOIN users u ON t.user_id = u.id
            WHERE t.id = $1
        """, teacher_id)

        roles = await conn.fetch("""
            SELECT role FROM role_assignments
            WHERE user_id = $1 AND revoked_at IS NULL
              AND (valid_to IS NULL OR valid_to > NOW())
        """, updated["user_id"])

        return TeacherResponse(
            id=str(updated["id"]),
            user_id=str(updated["user_id"]),
            email=updated["email"],
            name=updated["name"],
            teacher_code=updated["teacher_code"],
            title=updated["title"],
            first_name=updated["first_name"],
            last_name=updated["last_name"],
            is_active=updated["is_active"],
            roles=[r["role"] for r in roles],
        )


@router.delete("/teachers/{teacher_id}")
async def deactivate_teacher(
    teacher_id: str,
    user: Dict[str, Any] = Depends(get_current_user),
):
    """Deactivate a teacher (soft delete)"""
    pool = await get_pool()

    async with pool.acquire() as conn:
        result = await conn.execute("""
            UPDATE teachers SET is_active = false WHERE id = $1
        """, teacher_id)

        if result == "UPDATE 0":
            raise HTTPException(status_code=404, detail="Teacher not found")

        return {"status": "deactivated", "teacher_id": teacher_id}
