import logging
from datetime import datetime, timedelta
from fastapi import APIRouter, HTTPException, Query, Request
from fastapi.responses import Response

from app.core.database import execute_query

logger = logging.getLogger(__name__)
router = APIRouter()


def _parse_iso_datetime(value: str, fallback: datetime) -> datetime:
    if not value:
        return fallback
    try:
        return datetime.fromisoformat(value)
    except ValueError:
        return fallback


def _get_user_id(request: Request, user_id: int | None, only_mine: bool) -> int | None:
    if user_id is not None:
        return user_id
    state_user_id = getattr(request.state, "user_id", None)
    if state_user_id is not None:
        return int(state_user_id)
    if only_mine:
        raise HTTPException(status_code=401, detail="User not authenticated")
    return None


def _build_event(event_type: str, title: str, start_dt: datetime, url: str, extra: dict) -> dict:
    payload = {
        "id": f"{event_type}:{extra.get('reference_id')}",
        "title": title,
        "start": start_dt.isoformat(),
        "url": url,
        "event_type": event_type,
    }
    payload.update(extra)
    return payload


def _escape_ical(value: str) -> str:
    return (
        value.replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\n", "\\n")
    )


def _format_ical_dt(value: datetime) -> str:
    return value.strftime("%Y%m%dT%H%M%S")


def _get_calendar_events(
    request: Request,
    start_dt: datetime,
    end_dt: datetime,
    only_mine: bool,
    user_id: int | None,
    customer_id: int | None,
    types: str | None,
) -> list[dict]:
    allowed_types = {
        "case_deadline",
        "case_deferred",
        "case_reminder",
        "deadline",
        "deferred",
        "reminder",
        "meeting",
        "technician_visit",
        "obs",
    }
    requested_types = {
        t.strip() for t in (types.split(",") if types else []) if t.strip()
    }
    if requested_types and not requested_types.issubset(allowed_types):
        raise HTTPException(status_code=400, detail="Invalid event types")

    type_map = {
        "case_deadline": "deadline",
        "case_deferred": "deferred",
        "case_reminder": "reminder",
    }
    normalized_types = {type_map.get(t, t) for t in requested_types}
    reminder_kinds = {"reminder", "meeting", "technician_visit", "obs", "deadline"}

    include_deadline = not normalized_types or "deadline" in normalized_types
    include_deferred = not normalized_types or "deferred" in normalized_types
    include_reminder = not normalized_types or bool(reminder_kinds.intersection(normalized_types))

    resolved_user_id = _get_user_id(request, user_id, only_mine)
    events: list[dict] = []


    if include_deadline:
        query = """
            SELECT s.id, s.titel, s.deadline, s.customer_id, c.name as customer_name,
                   s.ansvarlig_bruger_id, s.created_by_user_id
            FROM sag_sager s
            LEFT JOIN customers c ON s.customer_id = c.id
            WHERE s.deleted_at IS NULL
              AND s.deadline IS NOT NULL
              AND s.deadline BETWEEN %s AND %s
        """
        params: list = [start_dt, end_dt]

        if only_mine and resolved_user_id is not None:
            query += " AND (s.ansvarlig_bruger_id = %s OR s.created_by_user_id = %s)"
            params.extend([resolved_user_id, resolved_user_id])

        if customer_id:
            query += " AND s.customer_id = %s"
            params.append(customer_id)

        rows = execute_query(query, tuple(params)) or []
        for row in rows:
            start_value = row.get("deadline")
            if not start_value:
                continue
            title = f"Deadline: {row.get('titel', 'Sag')}"
            events.append(
                _build_event(
                    "case_deadline",
                    title,
                    start_value,
                    f"/sag/{row.get('id')}/v3",
                    {
                        "reference_id": row.get("id"),
                        "reference_type": "case",
                        "event_kind": "deadline",
                        "customer_id": row.get("customer_id"),
                        "customer_name": row.get("customer_name"),
                        "status": "deadline",
                    },
                )
            )

    if include_deferred:
        query = """
            SELECT s.id, s.titel, s.deferred_until, s.customer_id, c.name as customer_name,
                   s.ansvarlig_bruger_id, s.created_by_user_id
            FROM sag_sager s
            LEFT JOIN customers c ON s.customer_id = c.id
            WHERE s.deleted_at IS NULL
              AND s.deferred_until IS NOT NULL
              AND s.deferred_until BETWEEN %s AND %s
        """
        params = [start_dt, end_dt]

        if only_mine and resolved_user_id is not None:
            query += " AND (s.ansvarlig_bruger_id = %s OR s.created_by_user_id = %s)"
            params.extend([resolved_user_id, resolved_user_id])

        if customer_id:
            query += " AND s.customer_id = %s"
            params.append(customer_id)

        rows = execute_query(query, tuple(params)) or []
        for row in rows:
            start_value = row.get("deferred_until")
            if not start_value:
                continue
            title = f"Defer: {row.get('titel', 'Sag')}"
            events.append(
                _build_event(
                    "case_deferred",
                    title,
                    start_value,
                    f"/sag/{row.get('id')}/v3",
                    {
                        "reference_id": row.get("id"),
                        "reference_type": "case",
                        "event_kind": "deferred",
                        "customer_id": row.get("customer_id"),
                        "customer_name": row.get("customer_name"),
                        "status": "deferred",
                    },
                )
            )

    if include_reminder:
        query = """
            SELECT r.id, r.title, r.message, r.priority, r.event_type, r.next_check_at, r.scheduled_at,
                   r.sag_id, s.titel as sag_title, s.customer_id, c.name as customer_name,
                   r.recipient_user_ids, r.created_by_user_id
            FROM sag_reminders r
            JOIN sag_sager s ON s.id = r.sag_id
            LEFT JOIN customers c ON s.customer_id = c.id
            WHERE r.deleted_at IS NULL
              AND r.is_active = true
              AND s.deleted_at IS NULL
              AND COALESCE(r.next_check_at, r.scheduled_at) BETWEEN %s AND %s
        """
        params = [start_dt, end_dt]

        requested_reminder_types = sorted(reminder_kinds.intersection(normalized_types))
        if requested_reminder_types:
            query += " AND r.event_type = ANY(%s)"
            params.append(requested_reminder_types)

        if only_mine and resolved_user_id is not None:
            query += " AND ((r.recipient_user_ids IS NOT NULL AND %s = ANY(r.recipient_user_ids)) OR r.created_by_user_id = %s)"
            params.extend([resolved_user_id, resolved_user_id])

        if customer_id:
            query += " AND s.customer_id = %s"
            params.append(customer_id)

        rows = execute_query(query, tuple(params)) or []
        for row in rows:
            start_value = row.get("next_check_at") or row.get("scheduled_at")
            if not start_value:
                continue
            title = f"Reminder: {row.get('title', 'Reminder')}"
            case_title = row.get("sag_title")
            if case_title:
                title = f"{title} · {case_title}"
            events.append(
                _build_event(
                    "case_reminder",
                    title,
                    start_value,
                    f"/sag/{row.get('sag_id')}/v3",
                    {
                        "reference_id": row.get("id"),
                        "reference_type": "reminder",
                        "case_id": row.get("sag_id"),
                        "event_kind": row.get("event_type") or "reminder",
                        "customer_id": row.get("customer_id"),
                        "customer_name": row.get("customer_name"),
                        "event_type": row.get("event_type"),
                        "priority": row.get("priority"),
                    },
                )
            )

    events.sort(key=lambda item: item.get("start") or "")

    return events


@router.get("/calendar/events")
async def get_calendar_events(
    request: Request,
    start: str = Query(None),
    end: str = Query(None),
    only_mine: bool = Query(True),
    user_id: int | None = Query(None),
    customer_id: int | None = Query(None),
    types: str | None = Query(None),
):
    """Aggregate calendar events from sag deadlines, deferred dates, and reminders."""
    now = datetime.now()
    start_dt = _parse_iso_datetime(start, now - timedelta(days=14))
    end_dt = _parse_iso_datetime(end, now + timedelta(days=60))

    if end_dt < start_dt:
        raise HTTPException(status_code=400, detail="Invalid date range")

    events = _get_calendar_events(
        request=request,
        start_dt=start_dt,
        end_dt=end_dt,
        only_mine=only_mine,
        user_id=user_id,
        customer_id=customer_id,
        types=types,
    )

    return {"events": events}


@router.get("/calendar/ical")
async def get_calendar_ical(
    request: Request,
    start: str = Query(None),
    end: str = Query(None),
    only_mine: bool = Query(True),
    user_id: int | None = Query(None),
    customer_id: int | None = Query(None),
    types: str | None = Query(None),
):
    """Serve calendar events as an iCal feed."""
    now = datetime.now()
    start_dt = _parse_iso_datetime(start, now - timedelta(days=14))
    end_dt = _parse_iso_datetime(end, now + timedelta(days=60))

    if end_dt < start_dt:
        raise HTTPException(status_code=400, detail="Invalid date range")

    events = _get_calendar_events(
        request=request,
        start_dt=start_dt,
        end_dt=end_dt,
        only_mine=only_mine,
        user_id=user_id,
        customer_id=customer_id,
        types=types,
    )

    lines = [
        "BEGIN:VCALENDAR",
        "VERSION:2.0",
        "PRODID:-//BMC Hub//Calendar//DA",
        "CALSCALE:GREGORIAN",
        "X-WR-CALNAME:BMC Hub Kalender",
    ]

    for event in events:
        start_value = datetime.fromisoformat(event.get("start"))
        summary = _escape_ical(event.get("title", ""))
        description_parts = []
        if event.get("customer_name"):
            description_parts.append(f"Kunde: {event.get('customer_name')}")
        if event.get("event_type"):
            description_parts.append(f"Type: {event.get('event_type')}")
        if event.get("url"):
            description_parts.append(f"Link: {event.get('url')}")
        description = _escape_ical("\n".join(description_parts))
        uid = _escape_ical(f"{event.get('id')}@bmc-hub")

        lines.extend([
            "BEGIN:VEVENT",
            f"UID:{uid}",
            f"DTSTAMP:{_format_ical_dt(now)}",
            f"DTSTART:{_format_ical_dt(start_value)}",
            f"SUMMARY:{summary}",
            f"DESCRIPTION:{description}",
            "END:VEVENT",
        ])

    lines.append("END:VCALENDAR")

    return Response(
        content="\r\n".join(lines),
        media_type="text/calendar; charset=utf-8",
    )
