from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import Optional, List
from pydantic import BaseModel
from datetime import date, timedelta
import calendar

from app.database import get_db
from app.models.daily_subscription import DailySubscription
from app.models.mass_template import MassTemplate
from app.models.template_position import TemplatePosition
from app.models.asim import Asim

router = APIRouter(prefix="/api/daily", tags=["Jadwal Harian"])

class SubscriptionCreate(BaseModel):
    asim_id: int
    template_id: int

def get_first_friday(year: int, month: int) -> date:
    """Get tanggal Jumat pertama di bulan tersebut"""
    d = date(year, month, 1)
    while d.weekday() != 4:  # 4 = Friday
        d += timedelta(days=1)
    return d

def _build_sub_dict(sub: DailySubscription, asim_map: dict, template_map: dict) -> dict:
    asim = asim_map.get(sub.asim_id)
    template = template_map.get(sub.template_id)
    return {
        "id": sub.id,
        "asim_id": sub.asim_id,
        "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,
        "template_id": sub.template_id,
        "template_name": template.name if template else None,
        "day_of_week": template.day_of_week if template else None,
        "time": template.time if template else None,
        "is_first_friday": template.is_first_friday if template else False,
        "is_active": sub.is_active,
        "created_at": str(sub.created_at),
    }

def enrich_subscription(sub: DailySubscription, db: Session) -> dict:
    """Single-item enrich — used after create. Uses individual queries (ok for single item)."""
    asim = db.query(Asim).filter(Asim.id == sub.asim_id).first()
    template = db.query(MassTemplate).filter(MassTemplate.id == sub.template_id).first()
    asim_map = {sub.asim_id: asim} if asim else {}
    template_map = {sub.template_id: template} if template else {}
    return _build_sub_dict(sub, asim_map, template_map)

@router.get("/templates")
def get_daily_templates(db: Session = Depends(get_db)):
    """Get semua template harian — batch query TemplatePositions"""
    templates = db.query(MassTemplate).filter(
        MassTemplate.mass_type == 'daily',
        MassTemplate.is_active == True,
    ).order_by(MassTemplate.day_of_week, MassTemplate.time).all()

    if not templates:
        return []

    # Batch: pre-fetch all positions for all templates in one query
    template_ids = [t.id for t in templates]
    all_positions = db.query(TemplatePosition).filter(
        TemplatePosition.template_id.in_(template_ids)
    ).all()
    position_count_map = {}
    for p in all_positions:
        position_count_map[p.template_id] = position_count_map.get(p.template_id, 0) + 1

    return [
        {
            "id": t.id,
            "name": t.name,
            "day_of_week": t.day_of_week,
            "time": t.time,
            "is_first_friday": t.is_first_friday,
            "position_count": position_count_map.get(t.id, 0),
        }
        for t in templates
    ]

@router.get("/subscriptions")
def get_subscriptions(template_id: Optional[int] = None, asim_id: Optional[int] = None, db: Session = Depends(get_db)):
    q = db.query(DailySubscription).filter(DailySubscription.is_active == True)
    if template_id:
        q = q.filter(DailySubscription.template_id == template_id)
    if asim_id:
        q = q.filter(DailySubscription.asim_id == asim_id)
    subs = q.all()
    if not subs:
        return []

    # Batch: pre-fetch all Asim and MassTemplate
    asim_ids = list({s.asim_id for s in subs})
    tmpl_ids = list({s.template_id for s in subs})
    asim_map = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()}
    template_map = {t.id: t for t in db.query(MassTemplate).filter(MassTemplate.id.in_(tmpl_ids)).all()}

    return [_build_sub_dict(s, asim_map, template_map) for s in subs]

@router.post("/subscriptions")
def create_subscription(data: SubscriptionCreate, db: Session = Depends(get_db)):
    # Cek sudah subscribe template ini belum
    existing = db.query(DailySubscription).filter(
        DailySubscription.asim_id == data.asim_id,
        DailySubscription.template_id == data.template_id,
        DailySubscription.is_active == True,
    ).first()
    if existing:
        raise HTTPException(status_code=400, detail="ASIM sudah subscribe misa ini!")

    # Cek kapasitas template
    template = db.query(MassTemplate).filter(MassTemplate.id == data.template_id).first()
    if not template:
        raise HTTPException(status_code=404, detail="Template tidak ditemukan")

    positions = db.query(TemplatePosition).filter(
        TemplatePosition.template_id == data.template_id
    ).all()
    max_capacity = len(positions)

    current_count = db.query(DailySubscription).filter(
        DailySubscription.template_id == data.template_id,
        DailySubscription.is_active == True,
    ).count()

    if current_count >= max_capacity:
        raise HTTPException(status_code=400, detail=f"Slot penuh! Kapasitas {max_capacity} orang.")

    sub = DailySubscription(
        asim_id=data.asim_id,
        template_id=data.template_id,
        day_of_week=template.day_of_week,
        mass_time=template.time,
        is_active=True,
    )
    db.add(sub)
    try:
        db.commit()
        db.refresh(sub)
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail="Gagal menyimpan subscription jadwal harian")
    return enrich_subscription(sub, db)

@router.delete("/subscriptions/{sub_id}")
def unsubscribe(sub_id: int, db: Session = Depends(get_db)):
    sub = db.query(DailySubscription).filter(DailySubscription.id == sub_id).first()
    if not sub:
        raise HTTPException(status_code=404, detail="Subscription tidak ditemukan")
    db.delete(sub)
    try:
        db.commit()
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail="Gagal menghapus subscription jadwal harian")
    return {"message": "Berhasil unsubscribe"}

@router.get("/schedule")
def get_daily_schedule(month: int, year: int, db: Session = Depends(get_db)):
    """Generate jadwal harian on-the-fly untuk bulan tertentu — batch queries"""
    first_friday = get_first_friday(year, month)
    days_in_month = calendar.monthrange(year, month)[1]

    # Ambil semua template harian
    templates = db.query(MassTemplate).filter(
        MassTemplate.mass_type == 'daily',
        MassTemplate.is_active == True,
    ).all()

    # Ambil semua subscription aktif
    subscriptions = db.query(DailySubscription).filter(
        DailySubscription.is_active == True
    ).all()

    # Batch: pre-fetch all Asim for all subscription asim_ids (no N+1)
    asim_ids = list({sub.asim_id for sub in subscriptions})
    asim_map = {a.id: a for a in db.query(Asim).filter(Asim.id.in_(asim_ids)).all()} if asim_ids else {}

    # Batch: pre-fetch all TemplatePositions for all templates (no N+1)
    template_ids = [t.id for t in templates]
    all_positions = db.query(TemplatePosition).filter(
        TemplatePosition.template_id.in_(template_ids)
    ).all() if template_ids else []
    position_count_map = {}
    for p in all_positions:
        position_count_map[p.template_id] = position_count_map.get(p.template_id, 0) + 1

    # Group subscriptions by template_id — using pre-loaded Asim map
    sub_by_template: dict = {}
    for sub in subscriptions:
        if sub.template_id not in sub_by_template:
            sub_by_template[sub.template_id] = []
        asim = asim_map.get(sub.asim_id)
        sub_by_template[sub.template_id].append({
            "sub_id": sub.id,
            "asim_id": sub.asim_id,
            "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,
        })

    # Group templates by day_of_week + is_first_friday
    result = []
    for d in range(1, days_in_month + 1):
        current_date = date(year, month, d)
        day_of_week = current_date.weekday()  # 0=Mon, 6=Sun
        is_first_friday_day = (current_date == first_friday)

        # Cari template yang sesuai
        for template in templates:
            if template.day_of_week != day_of_week:
                continue
            # Skip template first_friday kalau bukan Jumat pertama
            if template.is_first_friday and not is_first_friday_day:
                continue
            # Skip template non-first_friday kalau ini Jumat pertama (pakai yg first_friday)
            if not template.is_first_friday and is_first_friday_day and day_of_week == 4:
                # Cek apakah ada template first_friday untuk jam ini (in-memory, no query)
                has_first_friday_template = any(
                    t.day_of_week == 4 and t.is_first_friday and t.time == template.time
                    for t in templates
                )
                if has_first_friday_template:
                    continue

            result.append({
                "date": str(current_date),
                "day_name": current_date.strftime('%A'),
                "template_id": template.id,
                "template_name": template.name,
                "time": template.time,
                "is_first_friday": is_first_friday_day and template.is_first_friday,
                "position_count": position_count_map.get(template.id, 0),
                "subscribers": sub_by_template.get(template.id, []),
            })

    result.sort(key=lambda x: (x["date"], x["time"]))
    return result
