"""Calendar events REST API."""
from __future__ import annotations

from datetime import datetime, timezone

from quart import Blueprint, g, jsonify, request

from fabledassistant.auth import login_required
import fabledassistant.services.events as events_svc

events_bp = Blueprint("events", __name__, url_prefix="/api/events")


def _parse_dt(value: str) -> datetime:
    """Parse ISO 8601 datetime string, ensuring UTC-awareness."""
    dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)
    return dt


def _get_current_user_id() -> int:
    return g.user.id


@events_bp.get("")
@login_required
async def list_events():
    date_from_str = request.args.get("from")
    date_to_str = request.args.get("to")
    if not date_from_str or not date_to_str:
        return jsonify({"error": "from and to query params are required"}), 400
    try:
        date_from = _parse_dt(date_from_str)
        date_to = _parse_dt(date_to_str)
    except ValueError:
        return jsonify({"error": "Invalid datetime format"}), 400
    events = await events_svc.list_events(
        user_id=_get_current_user_id(),
        date_from=date_from,
        date_to=date_to,
    )
    return jsonify(events)


@events_bp.post("")
@login_required
async def create_event():
    data = await request.get_json() or {}
    if not data.get("title") or not data.get("start_dt"):
        return jsonify({"error": "title and start_dt are required"}), 400
    try:
        start_dt = _parse_dt(data["start_dt"])
        end_dt = _parse_dt(data["end_dt"]) if data.get("end_dt") else None
    except ValueError:
        return jsonify({"error": "Invalid datetime format"}), 400
    try:
        event = await events_svc.create_event(
            user_id=_get_current_user_id(),
            title=data["title"],
            start_dt=start_dt,
            end_dt=end_dt,
            duration_minutes=data.get("duration_minutes"),
            all_day=data.get("all_day", False),
            description=data.get("description", ""),
            location=data.get("location", ""),
            color=data.get("color", ""),
            recurrence=data.get("recurrence"),
            project_id=data.get("project_id"),
            reminder_minutes=data.get("reminder_minutes"),
        )
    except ValueError as exc:
        return jsonify({"error": str(exc)}), 400
    return jsonify(event.to_dict()), 201


@events_bp.get("/<int:event_id>")
@login_required
async def get_event(event_id: int):
    event = await events_svc.get_event(
        user_id=_get_current_user_id(),
        event_id=event_id,
    )
    if event is None:
        return jsonify({"error": "Event not found"}), 404
    return jsonify(event.to_dict())


@events_bp.patch("/<int:event_id>")
@login_required
async def update_event(event_id: int):
    data = await request.get_json() or {}
    fields: dict = {}
    for str_field in ("title", "description", "location", "color", "recurrence"):
        if str_field in data:
            fields[str_field] = data[str_field]
    for bool_field in ("all_day",):
        if bool_field in data:
            fields[bool_field] = data[bool_field]
    for int_field in ("project_id", "reminder_minutes", "duration_minutes"):
        if int_field in data:
            fields[int_field] = data[int_field]
    for dt_field in ("start_dt", "end_dt"):
        if dt_field in data:
            if data[dt_field] is None:
                # Explicit null clears the field (e.g. removing end_dt)
                fields[dt_field] = None
            elif data[dt_field]:
                try:
                    fields[dt_field] = _parse_dt(data[dt_field])
                except ValueError:
                    return jsonify({"error": f"Invalid datetime for {dt_field}"}), 400
    try:
        event = await events_svc.update_event(
            user_id=_get_current_user_id(),
            event_id=event_id,
            **fields,
        )
    except ValueError as exc:
        return jsonify({"error": str(exc)}), 400
    if event is None:
        return jsonify({"error": "Event not found"}), 404
    return jsonify(event.to_dict())


@events_bp.delete("/<int:event_id>")
@login_required
async def delete_event(event_id: int):
    event = await events_svc.get_event(
        user_id=_get_current_user_id(),
        event_id=event_id,
    )
    if event is None:
        return jsonify({"error": "Event not found"}), 404
    await events_svc.delete_event(
        user_id=_get_current_user_id(),
        event_id=event_id,
    )
    return "", 204


@events_bp.post("/sync")
@login_required
async def sync_caldav():
    """Trigger a CalDAV pull sync for the current user."""
    from fabledassistant.services.caldav_sync import sync_user_events
    result = await sync_user_events(user_id=_get_current_user_id())
    return jsonify(result)
