from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import date, timedelta
from pydantic import BaseModel
from app.database import get_db
from app.models.attendance import Attendance
from app.models.assignment import Assignment
from app.models.mass_schedule import MassSchedule
from app.models.mass_template import MassTemplate
from app.models.asim import Asim
from app.models.user import User
from app.models.system_setting import SystemSetting
from app.core.security import get_current_user, require_pengurus


def _resolve_today(test_date: Optional[str], db: Session) -> date:
    """In development mode, allow test_date override. Otherwise use today."""
    if test_date:
        dev = db.query(SystemSetting).filter(SystemSetting.key == "development_mode").first()
        if dev and dev.value == "true":
            return date.fromisoformat(test_date)
    return date.today()

router = APIRouter(prefix="/api/attendance", tags=["Attendance"])


def get_week_start(d: date) -> date:
    """Week starts on Saturday."""
    return d - timedelta(days=(d.weekday() - 5) % 7)


class AttendanceRecord(BaseModel):
    asim_id: int
    status: str  # 'hadir' or 'tidak_hadir'


class AttendanceSubmit(BaseModel):
    records: List[AttendanceRecord]


@router.get("/my-schedules")
def get_my_pj_schedules(
    test_date: Optional[str] = Query(None, description="Dev only: override today (YYYY-MM-DD)"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Get this week's schedules where the logged-in ASIM is PJ."""
    if not current_user.asim:
        raise HTTPException(status_code=403, detail="Akun tidak terhubung ke data ASIM")

    asim_id = current_user.asim.id
    today = _resolve_today(test_date, db)
    week_start = get_week_start(today)
    week_end = week_start + timedelta(days=6)

    # Find assignments where this ASIM is PJ this week
    pj_assignments = (
        db.query(Assignment)
        .join(MassSchedule)
        .filter(
            Assignment.asim_id == asim_id,
            Assignment.position_type_code == "PJ",
            MassSchedule.date >= week_start,
            MassSchedule.date <= week_end,
            MassSchedule.is_published == True,
        )
        .all()
    )

    result = []
    for a in pj_assignments:
        schedule = a.schedule
        template = db.query(MassTemplate).filter(MassTemplate.id == schedule.template_id).first()

        # Get all assignments for this schedule
        all_assignments = (
            db.query(Assignment)
            .filter(
                Assignment.schedule_id == schedule.id,
                Assignment.asim_id.isnot(None),
            )
            .all()
        )

        # Get ASIMs
        asim_ids = [x.asim_id for x in all_assignments]
        asims = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()}

        # Get existing attendance records
        existing = db.query(Attendance).filter(Attendance.schedule_id == schedule.id).all()
        attendance_map = {r.asim_id: r.status for r in existing}

        members = []
        for assign in all_assignments:
            asim_obj = asims.get(assign.asim_id)
            if not asim_obj:
                continue
            members.append({
                "asim_id": asim_obj.id,
                "no_asim": asim_obj.no_asim,
                "full_name": asim_obj.full_name,
                "position_type_code": assign.position_type_code,
                "position_number": assign.position_number,
                "status": attendance_map.get(asim_obj.id),
            })

        result.append({
            "schedule_id": schedule.id,
            "date": schedule.date.isoformat(),
            "time": template.time if template else "-",
            "label": template.name if template else "-",
            "members": members,
            "submitted": len(attendance_map) > 0,
        })

    return result


@router.get("/{schedule_id}")
def get_attendance(
    schedule_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Get attendance records for a specific schedule."""
    schedule = db.query(MassSchedule).filter(MassSchedule.id == schedule_id).first()
    if not schedule:
        raise HTTPException(status_code=404, detail="Jadwal tidak ditemukan")

    records = db.query(Attendance).filter(Attendance.schedule_id == schedule_id).all()
    asim_ids = [r.asim_id for r in records]
    asims = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()}

    return [
        {
            "id": r.id,
            "asim_id": r.asim_id,
            "no_asim": asims[r.asim_id].no_asim if r.asim_id in asims else None,
            "full_name": asims[r.asim_id].full_name if r.asim_id in asims else "-",
            "status": r.status,
            "recorded_at": r.recorded_at.isoformat() if r.recorded_at else None,
        }
        for r in records
    ]


@router.post("/{schedule_id}")
def submit_attendance(
    schedule_id: int,
    body: AttendanceSubmit,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Submit or update attendance for a schedule. Only PJ of that schedule can submit."""
    if not current_user.asim:
        raise HTTPException(status_code=403, detail="Akun tidak terhubung ke data ASIM")

    # Verify this user is PJ for this schedule
    pj_check = (
        db.query(Assignment)
        .filter(
            Assignment.schedule_id == schedule_id,
            Assignment.asim_id == current_user.asim.id,
            Assignment.position_type_code == "PJ",
        )
        .first()
    )
    if not pj_check and current_user.role not in ("pengurus", "super_admin"):
        raise HTTPException(status_code=403, detail="Hanya PJ yang bisa mengisi absensi")

    # Validate status values
    for rec in body.records:
        if rec.status not in ("hadir", "tidak_hadir"):
            raise HTTPException(status_code=400, detail=f"Status tidak valid: {rec.status}")

    # Upsert each record
    for rec in body.records:
        existing = (
            db.query(Attendance)
            .filter(
                Attendance.schedule_id == schedule_id,
                Attendance.asim_id == rec.asim_id,
            )
            .first()
        )
        if existing:
            existing.status = rec.status
            existing.recorded_by_id = current_user.id
        else:
            new_rec = Attendance(
                schedule_id=schedule_id,
                asim_id=rec.asim_id,
                status=rec.status,
                recorded_by_id=current_user.id,
            )
            db.add(new_rec)

    try:
        db.commit()
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail="Gagal menyimpan absensi")

    return {"message": "Absensi berhasil disimpan"}


@router.get("/report/list")
def get_attendance_report(
    month: int = Query(...),
    year: int = Query(...),
    asim_id: Optional[int] = Query(None),
    db: Session = Depends(get_db),
    _: User = Depends(require_pengurus),
):
    """Admin report: attendance by month/year, optionally filtered by ASIM."""
    from sqlalchemy import extract

    query = (
        db.query(Attendance)
        .join(MassSchedule, Attendance.schedule_id == MassSchedule.id)
        .filter(
            extract("month", MassSchedule.date) == month,
            extract("year", MassSchedule.date) == year,
        )
    )

    if asim_id:
        query = query.filter(Attendance.asim_id == asim_id)

    records = query.all()

    # Batch load related data
    schedule_ids = list({r.schedule_id for r in records})
    asim_ids = list({r.asim_id for r in records})

    schedules = {s.id: s for s in db.query(MassSchedule).filter(MassSchedule.id.in_(schedule_ids)).all()}
    asims = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()}
    template_ids = [s.template_id for s in schedules.values() if s.template_id]
    templates = {t.id: t for t in db.query(MassTemplate).filter(MassTemplate.id.in_(template_ids)).all()}

    result = []
    for r in records:
        s = schedules.get(r.schedule_id)
        asim = asims.get(r.asim_id)
        tmpl = templates.get(s.template_id) if s and s.template_id else None
        result.append({
            "id": r.id,
            "schedule_id": r.schedule_id,
            "date": s.date.isoformat() if s else None,
            "time": tmpl.time if tmpl else "-",
            "label": tmpl.name if tmpl else "-",
            "asim_id": r.asim_id,
            "no_asim": asim.no_asim if asim else None,
            "full_name": asim.full_name if asim else "-",
            "status": r.status,
            "recorded_at": r.recorded_at.isoformat() if r.recorded_at else None,
        })

    return result
