from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
from app.database import get_db
from app.core.security import require_pengurus
from app.models.seat_layout import SeatLayout
from app.models.mass_template import MassTemplate
from app.models.special_mass import SpecialMass
from app.models.mass_schedule import MassSchedule
from app.models.assignment import Assignment
from app.models.asim import Asim
from app.models.position_type import PositionType
from app.schemas.seat_layout import SeatLayoutItem, SeatLayoutSave, SeatLayoutResponse, SeatLayoutWithAssignment
from app.helpers.crud import get_or_404

router = APIRouter(prefix="/api/seat-layout", tags=["seat-layout"])

VALID_VIEW_TYPES = {"duduk", "altar"}


def _validate_view_type(view_type: str):
    if view_type not in VALID_VIEW_TYPES:
        raise HTTPException(status_code=400, detail="view_type harus 'duduk' atau 'altar'")


# ── Template layout ───────────────────────────────────────────

@router.get("/template/{template_id}/{view_type}", response_model=List[SeatLayoutResponse])
def get_template_layout(template_id: int, view_type: str, db: Session = Depends(get_db)):
    _validate_view_type(view_type)
    get_or_404(db, MassTemplate, template_id, "Template")
    rows = db.query(SeatLayout).filter(
        SeatLayout.template_id == template_id,
        SeatLayout.view_type == view_type,
    ).order_by(SeatLayout.row_index, SeatLayout.col_index).all()
    return rows


@router.put("/template/{template_id}/{view_type}")
def save_template_layout(
    template_id: int, view_type: str, data: SeatLayoutSave,
    db: Session = Depends(get_db), _: object = Depends(require_pengurus),
):
    _validate_view_type(view_type)
    get_or_404(db, MassTemplate, template_id, "Template")
    # Delete existing layout for this view
    db.query(SeatLayout).filter(
        SeatLayout.template_id == template_id,
        SeatLayout.view_type == view_type,
    ).delete()
    # Insert new cells
    for item in data.items:
        db.add(SeatLayout(
            template_id=template_id,
            position_number=item.position_number,
            view_type=view_type,
            row_index=item.row_index,
            col_index=item.col_index,
            side=item.side,
            section=item.section,
        ))
    try:
        db.commit()
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail="Gagal menyimpan denah")
    return {"message": "Denah berhasil disimpan"}


# ── Special mass layout ──────────────────────────────────────

@router.get("/special/{special_mass_id}/{view_type}", response_model=List[SeatLayoutResponse])
def get_special_layout(special_mass_id: int, view_type: str, db: Session = Depends(get_db)):
    _validate_view_type(view_type)
    get_or_404(db, SpecialMass, special_mass_id, "Acara")
    rows = db.query(SeatLayout).filter(
        SeatLayout.special_mass_id == special_mass_id,
        SeatLayout.view_type == view_type,
    ).order_by(SeatLayout.row_index, SeatLayout.col_index).all()
    return rows


@router.put("/special/{special_mass_id}/{view_type}")
def save_special_layout(
    special_mass_id: int, view_type: str, data: SeatLayoutSave,
    db: Session = Depends(get_db), _: object = Depends(require_pengurus),
):
    _validate_view_type(view_type)
    get_or_404(db, SpecialMass, special_mass_id, "Acara")
    db.query(SeatLayout).filter(
        SeatLayout.special_mass_id == special_mass_id,
        SeatLayout.view_type == view_type,
    ).delete()
    for item in data.items:
        db.add(SeatLayout(
            special_mass_id=special_mass_id,
            position_number=item.position_number,
            view_type=view_type,
            row_index=item.row_index,
            col_index=item.col_index,
            side=item.side,
            section=item.section,
        ))
    try:
        db.commit()
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail="Gagal menyimpan denah")
    return {"message": "Denah berhasil disimpan"}


# ── Schedule layout (read-only, merges assignments) ──────────

@router.get("/schedule/{schedule_id}/{view_type}", response_model=List[SeatLayoutWithAssignment])
def get_schedule_layout(schedule_id: int, view_type: str, db: Session = Depends(get_db)):
    _validate_view_type(view_type)
    schedule = get_or_404(db, MassSchedule, schedule_id, "Jadwal")

    # Determine parent and fetch layout
    if schedule.template_id:
        layout_rows = db.query(SeatLayout).filter(
            SeatLayout.template_id == schedule.template_id,
            SeatLayout.view_type == view_type,
        ).order_by(SeatLayout.row_index, SeatLayout.col_index).all()
    elif schedule.special_mass_id:
        layout_rows = db.query(SeatLayout).filter(
            SeatLayout.special_mass_id == schedule.special_mass_id,
            SeatLayout.view_type == view_type,
        ).order_by(SeatLayout.row_index, SeatLayout.col_index).all()
    else:
        return []

    if not layout_rows:
        return []

    # Batch-load assignments for this schedule
    assignments = db.query(Assignment).filter(Assignment.schedule_id == schedule_id).all()
    assign_map = {a.position_number: a for a in assignments}

    # Batch-load ASIMs
    asim_ids = {a.asim_id for a in assignments if a.asim_id}
    asim_map = {}
    if asim_ids:
        asim_map = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()}

    # Batch-load position types
    type_codes = {a.position_type_code for a in assignments if a.position_type_code}
    ptype_map = {}
    if type_codes:
        ptype_map = {pt.code: pt for pt in db.query(PositionType).filter(PositionType.code.in_(type_codes)).all()}

    # Merge layout + assignments
    result = []
    for cell in layout_rows:
        a = assign_map.get(cell.position_number)
        asim = asim_map.get(a.asim_id) if a and a.asim_id else None
        pt = ptype_map.get(a.position_type_code) if a else None
        result.append(SeatLayoutWithAssignment(
            id=cell.id,
            position_number=cell.position_number,
            row_index=cell.row_index,
            col_index=cell.col_index,
            side=cell.side,
            section=cell.section,
            asim_id=asim.id if asim else None,
            asim_name=asim.full_name if asim else None,
            asim_no=asim.no_asim if asim else None,
            asim_photo=asim.photo if asim else None,
            position_type_code=a.position_type_code if a else None,
            position_type_label=pt.label if pt else None,
            position_type_color=pt.color if pt else None,
        ))
    return result
