"""
Schools API - School CRUD & Stats Routes.

List, get, stats, and bulk-import endpoints for schools.
"""

import logging
from typing import Optional

from fastapi import APIRouter, HTTPException, Query

from .schools_db import get_db_pool
from .schools_models import (
    SchoolResponse,
    SchoolsListResponse,
    SchoolStatsResponse,
    SchoolTypeResponse,
    BulkImportRequest,
    BulkImportResponse,
)

logger = logging.getLogger(__name__)

router = APIRouter(tags=["schools"])


# =============================================================================
# School Type Endpoints
# =============================================================================


@router.get("/types", response_model=list[SchoolTypeResponse])
async def list_school_types():
    """List all school types."""
    pool = await get_db_pool()
    async with pool.acquire() as conn:
        rows = await conn.fetch("""
            SELECT id, name, name_short, category, description
            FROM school_types
            ORDER BY category, name
        """)
        return [
            SchoolTypeResponse(
                id=str(row["id"]),
                name=row["name"],
                name_short=row["name_short"],
                category=row["category"],
                description=row["description"],
            )
            for row in rows
        ]


# =============================================================================
# School Endpoints
# =============================================================================


@router.get("", response_model=SchoolsListResponse)
async def list_schools(
    state: Optional[str] = Query(None, description="Filter by state code (BW, BY, etc.)"),
    school_type: Optional[str] = Query(None, description="Filter by school type name"),
    city: Optional[str] = Query(None, description="Filter by city"),
    district: Optional[str] = Query(None, description="Filter by district"),
    postal_code: Optional[str] = Query(None, description="Filter by postal code prefix"),
    search: Optional[str] = Query(None, description="Search in name, city"),
    has_email: Optional[bool] = Query(None, description="Filter schools with email"),
    has_website: Optional[bool] = Query(None, description="Filter schools with website"),
    is_public: Optional[bool] = Query(None, description="Filter public/private schools"),
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=200),
):
    """List schools with optional filtering and pagination."""
    pool = await get_db_pool()
    async with pool.acquire() as conn:
        # Build WHERE clause
        conditions = ["s.is_active = TRUE"]
        params = []
        param_idx = 1

        if state:
            conditions.append(f"s.state = ${param_idx}")
            params.append(state.upper())
            param_idx += 1

        if school_type:
            conditions.append(f"st.name = ${param_idx}")
            params.append(school_type)
            param_idx += 1

        if city:
            conditions.append(f"LOWER(s.city) = LOWER(${param_idx})")
            params.append(city)
            param_idx += 1

        if district:
            conditions.append(f"LOWER(s.district) LIKE LOWER(${param_idx})")
            params.append(f"%{district}%")
            param_idx += 1

        if postal_code:
            conditions.append(f"s.postal_code LIKE ${param_idx}")
            params.append(f"{postal_code}%")
            param_idx += 1

        if search:
            conditions.append(f"""
                (LOWER(s.name) LIKE LOWER(${param_idx})
                 OR LOWER(s.city) LIKE LOWER(${param_idx})
                 OR LOWER(s.district) LIKE LOWER(${param_idx}))
            """)
            params.append(f"%{search}%")
            param_idx += 1

        if has_email is not None:
            if has_email:
                conditions.append("s.email IS NOT NULL")
            else:
                conditions.append("s.email IS NULL")

        if has_website is not None:
            if has_website:
                conditions.append("s.website IS NOT NULL")
            else:
                conditions.append("s.website IS NULL")

        if is_public is not None:
            conditions.append(f"s.is_public = ${param_idx}")
            params.append(is_public)
            param_idx += 1

        where_clause = " AND ".join(conditions)

        # Count total
        count_query = f"""
            SELECT COUNT(*) FROM schools s
            LEFT JOIN school_types st ON s.school_type_id = st.id
            WHERE {where_clause}
        """
        total = await conn.fetchval(count_query, *params)

        # Fetch schools
        offset = (page - 1) * page_size
        query = f"""
            SELECT
                s.id, s.name, s.school_number, s.state, s.district, s.city,
                s.postal_code, s.street, s.address_full, s.latitude, s.longitude,
                s.website, s.email, s.phone, s.fax,
                s.principal_name, s.principal_email,
                s.student_count, s.teacher_count,
                s.is_public, s.is_all_day, s.source, s.crawled_at,
                s.is_active, s.created_at, s.updated_at,
                st.name as school_type, st.name_short as school_type_short, st.category as school_category,
                (SELECT COUNT(*) FROM school_staff ss WHERE ss.school_id = s.id AND ss.is_active = TRUE) as staff_count
            FROM schools s
            LEFT JOIN school_types st ON s.school_type_id = st.id
            WHERE {where_clause}
            ORDER BY s.state, s.city, s.name
            LIMIT ${param_idx} OFFSET ${param_idx + 1}
        """
        params.extend([page_size, offset])
        rows = await conn.fetch(query, *params)

        schools = [
            SchoolResponse(
                id=str(row["id"]),
                name=row["name"],
                school_number=row["school_number"],
                school_type=row["school_type"],
                school_type_short=row["school_type_short"],
                school_category=row["school_category"],
                state=row["state"],
                district=row["district"],
                city=row["city"],
                postal_code=row["postal_code"],
                street=row["street"],
                address_full=row["address_full"],
                latitude=row["latitude"],
                longitude=row["longitude"],
                website=row["website"],
                email=row["email"],
                phone=row["phone"],
                fax=row["fax"],
                principal_name=row["principal_name"],
                principal_email=row["principal_email"],
                student_count=row["student_count"],
                teacher_count=row["teacher_count"],
                is_public=row["is_public"],
                is_all_day=row["is_all_day"],
                staff_count=row["staff_count"],
                source=row["source"],
                crawled_at=row["crawled_at"],
                is_active=row["is_active"],
                created_at=row["created_at"],
                updated_at=row["updated_at"],
            )
            for row in rows
        ]

        return SchoolsListResponse(
            schools=schools,
            total=total,
            page=page,
            page_size=page_size,
        )


@router.get("/stats", response_model=SchoolStatsResponse)
async def get_school_stats():
    """Get school statistics."""
    pool = await get_db_pool()
    async with pool.acquire() as conn:
        # Total schools and staff
        totals = await conn.fetchrow("""
            SELECT
                (SELECT COUNT(*) FROM schools WHERE is_active = TRUE) as total_schools,
                (SELECT COUNT(*) FROM school_staff WHERE is_active = TRUE) as total_staff,
                (SELECT COUNT(*) FROM schools WHERE is_active = TRUE AND website IS NOT NULL) as with_website,
                (SELECT COUNT(*) FROM schools WHERE is_active = TRUE AND email IS NOT NULL) as with_email,
                (SELECT COUNT(*) FROM schools WHERE is_active = TRUE AND principal_name IS NOT NULL) as with_principal,
                (SELECT COALESCE(SUM(student_count), 0) FROM schools WHERE is_active = TRUE) as total_students,
                (SELECT COALESCE(SUM(teacher_count), 0) FROM schools WHERE is_active = TRUE) as total_teachers,
                (SELECT MAX(crawled_at) FROM schools) as last_crawl
        """)

        # By state
        state_rows = await conn.fetch("""
            SELECT state, COUNT(*) as count
            FROM schools
            WHERE is_active = TRUE
            GROUP BY state
            ORDER BY state
        """)
        schools_by_state = {row["state"]: row["count"] for row in state_rows}

        # By type
        type_rows = await conn.fetch("""
            SELECT COALESCE(st.name, 'Unbekannt') as type_name, COUNT(*) as count
            FROM schools s
            LEFT JOIN school_types st ON s.school_type_id = st.id
            WHERE s.is_active = TRUE
            GROUP BY st.name
            ORDER BY count DESC
        """)
        schools_by_type = {row["type_name"]: row["count"] for row in type_rows}

        return SchoolStatsResponse(
            total_schools=totals["total_schools"],
            total_staff=totals["total_staff"],
            schools_by_state=schools_by_state,
            schools_by_type=schools_by_type,
            schools_with_website=totals["with_website"],
            schools_with_email=totals["with_email"],
            schools_with_principal=totals["with_principal"],
            total_students=totals["total_students"],
            total_teachers=totals["total_teachers"],
            last_crawl_time=totals["last_crawl"],
        )


@router.get("/{school_id}", response_model=SchoolResponse)
async def get_school(school_id: str):
    """Get a single school by ID."""
    pool = await get_db_pool()
    async with pool.acquire() as conn:
        row = await conn.fetchrow("""
            SELECT
                s.id, s.name, s.school_number, s.state, s.district, s.city,
                s.postal_code, s.street, s.address_full, s.latitude, s.longitude,
                s.website, s.email, s.phone, s.fax,
                s.principal_name, s.principal_email,
                s.student_count, s.teacher_count,
                s.is_public, s.is_all_day, s.source, s.crawled_at,
                s.is_active, s.created_at, s.updated_at,
                st.name as school_type, st.name_short as school_type_short, st.category as school_category,
                (SELECT COUNT(*) FROM school_staff ss WHERE ss.school_id = s.id AND ss.is_active = TRUE) as staff_count
            FROM schools s
            LEFT JOIN school_types st ON s.school_type_id = st.id
            WHERE s.id = $1
        """, school_id)

        if not row:
            raise HTTPException(status_code=404, detail="School not found")

        return SchoolResponse(
            id=str(row["id"]),
            name=row["name"],
            school_number=row["school_number"],
            school_type=row["school_type"],
            school_type_short=row["school_type_short"],
            school_category=row["school_category"],
            state=row["state"],
            district=row["district"],
            city=row["city"],
            postal_code=row["postal_code"],
            street=row["street"],
            address_full=row["address_full"],
            latitude=row["latitude"],
            longitude=row["longitude"],
            website=row["website"],
            email=row["email"],
            phone=row["phone"],
            fax=row["fax"],
            principal_name=row["principal_name"],
            principal_email=row["principal_email"],
            student_count=row["student_count"],
            teacher_count=row["teacher_count"],
            is_public=row["is_public"],
            is_all_day=row["is_all_day"],
            staff_count=row["staff_count"],
            source=row["source"],
            crawled_at=row["crawled_at"],
            is_active=row["is_active"],
            created_at=row["created_at"],
            updated_at=row["updated_at"],
        )


@router.post("/bulk-import", response_model=BulkImportResponse)
async def bulk_import_schools(request: BulkImportRequest):
    """Bulk import schools. Updates existing schools based on school_number + state."""
    pool = await get_db_pool()
    imported = 0
    updated = 0
    skipped = 0
    errors = []

    async with pool.acquire() as conn:
        # Get school type mapping
        type_rows = await conn.fetch("SELECT id, name FROM school_types")
        type_map = {row["name"].lower(): str(row["id"]) for row in type_rows}

        for school in request.schools:
            try:
                # Find school type ID
                school_type_id = None
                if school.school_type_raw:
                    school_type_id = type_map.get(school.school_type_raw.lower())

                # Check if school exists (by school_number + state, or by name + city + state)
                existing = None
                if school.school_number:
                    existing = await conn.fetchrow(
                        "SELECT id FROM schools WHERE school_number = $1 AND state = $2",
                        school.school_number, school.state
                    )
                if not existing and school.city:
                    existing = await conn.fetchrow(
                        "SELECT id FROM schools WHERE LOWER(name) = LOWER($1) AND LOWER(city) = LOWER($2) AND state = $3",
                        school.name, school.city, school.state
                    )

                if existing:
                    # Update existing school
                    await conn.execute("""
                        UPDATE schools SET
                            name = $2,
                            school_type_id = COALESCE($3, school_type_id),
                            school_type_raw = COALESCE($4, school_type_raw),
                            district = COALESCE($5, district),
                            city = COALESCE($6, city),
                            postal_code = COALESCE($7, postal_code),
                            street = COALESCE($8, street),
                            address_full = COALESCE($9, address_full),
                            latitude = COALESCE($10, latitude),
                            longitude = COALESCE($11, longitude),
                            website = COALESCE($12, website),
                            email = COALESCE($13, email),
                            phone = COALESCE($14, phone),
                            fax = COALESCE($15, fax),
                            principal_name = COALESCE($16, principal_name),
                            principal_title = COALESCE($17, principal_title),
                            principal_email = COALESCE($18, principal_email),
                            principal_phone = COALESCE($19, principal_phone),
                            student_count = COALESCE($20, student_count),
                            teacher_count = COALESCE($21, teacher_count),
                            is_public = $22,
                            source = COALESCE($23, source),
                            source_url = COALESCE($24, source_url),
                            updated_at = NOW()
                        WHERE id = $1
                    """,
                        existing["id"],
                        school.name,
                        school_type_id,
                        school.school_type_raw,
                        school.district,
                        school.city,
                        school.postal_code,
                        school.street,
                        school.address_full,
                        school.latitude,
                        school.longitude,
                        school.website,
                        school.email,
                        school.phone,
                        school.fax,
                        school.principal_name,
                        school.principal_title,
                        school.principal_email,
                        school.principal_phone,
                        school.student_count,
                        school.teacher_count,
                        school.is_public,
                        school.source,
                        school.source_url,
                    )
                    updated += 1
                else:
                    # Insert new school
                    await conn.execute("""
                        INSERT INTO schools (
                            name, school_number, school_type_id, school_type_raw,
                            state, district, city, postal_code, street, address_full,
                            latitude, longitude, website, email, phone, fax,
                            principal_name, principal_title, principal_email, principal_phone,
                            student_count, teacher_count, is_public,
                            source, source_url, crawled_at
                        ) VALUES (
                            $1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
                            $11, $12, $13, $14, $15, $16, $17, $18, $19, $20,
                            $21, $22, $23, $24, $25, NOW()
                        )
                    """,
                        school.name,
                        school.school_number,
                        school_type_id,
                        school.school_type_raw,
                        school.state,
                        school.district,
                        school.city,
                        school.postal_code,
                        school.street,
                        school.address_full,
                        school.latitude,
                        school.longitude,
                        school.website,
                        school.email,
                        school.phone,
                        school.fax,
                        school.principal_name,
                        school.principal_title,
                        school.principal_email,
                        school.principal_phone,
                        school.student_count,
                        school.teacher_count,
                        school.is_public,
                        school.source,
                        school.source_url,
                    )
                    imported += 1

            except Exception as e:
                errors.append(f"Error importing {school.name}: {str(e)}")
                if len(errors) > 100:
                    errors.append("... (more errors truncated)")
                    break

    return BulkImportResponse(
        imported=imported,
        updated=updated,
        skipped=skipped,
        errors=errors[:100],
    )
