"""
Rest Days Endpoints for Mitai Jinkendo

Context-specific rest days with flexible JSONB configuration.
"""
import logging
from typing import Optional, Literal
from datetime import datetime, timedelta

from fastapi import APIRouter, HTTPException, Depends, Header
from pydantic import BaseModel, Field
from psycopg2.extras import Json
from psycopg2.errors import UniqueViolation

from db import get_db, get_cursor, r2d
from auth import require_auth
from routers.profiles import get_pid

router = APIRouter(prefix="/api/rest-days", tags=["rest-days"])
logger = logging.getLogger(__name__)


# ── Models ────────────────────────────────────────────────────────────────────

class RestConfig(BaseModel):
    focus: Literal['muscle_recovery', 'cardio_recovery', 'mental_rest', 'deload', 'injury']
    rest_from: list[str] = Field(default_factory=list, description="Training type IDs to avoid")
    allows: list[str] = Field(default_factory=list, description="Allowed activity type IDs")
    intensity_max: Optional[int] = Field(None, ge=1, le=100, description="Max HR% for allowed activities")
    note: str = ""


class RestDayCreate(BaseModel):
    date: str  # YYYY-MM-DD
    rest_config: RestConfig
    note: str = ""


class RestDayUpdate(BaseModel):
    date: Optional[str] = None
    rest_config: Optional[RestConfig] = None
    note: Optional[str] = None


class ActivityConflictCheck(BaseModel):
    date: str
    activity_type: str


# ── CRUD Endpoints ────────────────────────────────────────────────────────────

@router.get("")
def list_rest_days(
    limit: int = 90,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """List rest days for current profile (last N days)."""
    pid = get_pid(x_profile_id)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT id, profile_id, date, rest_config, note, created_at
            FROM rest_days
            WHERE profile_id = %s
            ORDER BY date DESC
            LIMIT %s
            """,
            (pid, limit)
        )
        return [r2d(r) for r in cur.fetchall()]


@router.post("")
def create_rest_day(
    data: RestDayCreate,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Create rest day with JSONB config. Upserts by date."""
    pid = get_pid(x_profile_id)

    # Validate date format
    try:
        datetime.strptime(data.date, '%Y-%m-%d')
    except ValueError:
        raise HTTPException(400, "Invalid date format. Use YYYY-MM-DD")

    # Convert RestConfig to dict for JSONB storage
    config_dict = data.rest_config.model_dump()
    focus = data.rest_config.focus

    try:
        with get_db() as conn:
            cur = get_cursor(conn)

            # Insert (multiple entries per date allowed, but not same focus)
            cur.execute(
                """
                INSERT INTO rest_days (profile_id, date, focus, rest_config, note, created_at)
                VALUES (%s, %s, %s, %s, %s, CURRENT_TIMESTAMP)
                RETURNING id, profile_id, date, focus, rest_config, note, created_at
                """,
                (pid, data.date, focus, Json(config_dict), data.note)
            )

            result = cur.fetchone()
            return r2d(result)
    except UniqueViolation:
        # User-friendly error for duplicate focus
        focus_labels = {
            'muscle_recovery': 'Muskelregeneration',
            'cardio_recovery': 'Cardio-Erholung',
            'mental_rest': 'Mentale Erholung',
            'deload': 'Deload',
            'injury': 'Verletzungspause',
        }
        focus_label = focus_labels.get(focus, focus)
        raise HTTPException(
            400,
            f"Du hast bereits einen Ruhetag '{focus_label}' für {data.date}. Bitte wähle einen anderen Typ oder lösche den bestehenden Eintrag."
        )


@router.get("/{rest_day_id}")
def get_rest_day(
    rest_day_id: int,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Get single rest day by ID."""
    pid = get_pid(x_profile_id)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT id, profile_id, date, rest_config, note, created_at
            FROM rest_days
            WHERE id = %s AND profile_id = %s
            """,
            (rest_day_id, pid)
        )

        row = cur.fetchone()
        if not row:
            raise HTTPException(404, "Rest day not found")

        return r2d(row)


@router.put("/{rest_day_id}")
def update_rest_day(
    rest_day_id: int,
    data: RestDayUpdate,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Update rest day."""
    pid = get_pid(x_profile_id)

    # Build update fields dynamically
    updates = []
    values = []

    if data.date:
        try:
            datetime.strptime(data.date, '%Y-%m-%d')
        except ValueError:
            raise HTTPException(400, "Invalid date format. Use YYYY-MM-DD")
        updates.append("date = %s")
        values.append(data.date)

    if data.rest_config:
        updates.append("rest_config = %s")
        values.append(Json(data.rest_config.model_dump()))
        # Also update focus column if config changed
        updates.append("focus = %s")
        values.append(data.rest_config.focus)

    if data.note is not None:
        updates.append("note = %s")
        values.append(data.note)

    if not updates:
        raise HTTPException(400, "No fields to update")

    values.extend([rest_day_id, pid])

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            f"""
            UPDATE rest_days
            SET {', '.join(updates)}
            WHERE id = %s AND profile_id = %s
            RETURNING id, profile_id, date, rest_config, note, created_at
            """,
            values
        )

        result = cur.fetchone()
        if not result:
            raise HTTPException(404, "Rest day not found")

        return r2d(result)


@router.delete("/{rest_day_id}")
def delete_rest_day(
    rest_day_id: int,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Delete rest day."""
    pid = get_pid(x_profile_id)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            "DELETE FROM rest_days WHERE id = %s AND profile_id = %s RETURNING id",
            (rest_day_id, pid)
        )

        result = cur.fetchone()
        if not result:
            raise HTTPException(404, "Rest day not found")

        return {"deleted": True, "id": result['id']}


# ── Stats & Validation ────────────────────────────────────────────────────────

@router.get("/stats")
def get_rest_days_stats(
    weeks: int = 4,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Get rest day statistics (count per week, focus distribution)."""
    pid = get_pid(x_profile_id)

    cutoff_date = (datetime.now() - timedelta(weeks=weeks)).strftime('%Y-%m-%d')

    with get_db() as conn:
        cur = get_cursor(conn)

        # Total count
        cur.execute(
            """
            SELECT COUNT(*) as total
            FROM rest_days
            WHERE profile_id = %s AND date >= %s
            """,
            (pid, cutoff_date)
        )
        total = cur.fetchone()['total']

        # Count by focus type
        cur.execute(
            """
            SELECT
                rest_config->>'focus' as focus,
                COUNT(*) as count
            FROM rest_days
            WHERE profile_id = %s AND date >= %s
            GROUP BY rest_config->>'focus'
            ORDER BY count DESC
            """,
            (pid, cutoff_date)
        )
        by_focus = [r2d(r) for r in cur.fetchall()]

        # Count by week (ISO week number)
        cur.execute(
            """
            SELECT
                EXTRACT(YEAR FROM date) as year,
                EXTRACT(WEEK FROM date) as week,
                COUNT(*) as count
            FROM rest_days
            WHERE profile_id = %s AND date >= %s
            GROUP BY year, week
            ORDER BY year DESC, week DESC
            """,
            (pid, cutoff_date)
        )
        by_week = [r2d(r) for r in cur.fetchall()]

        return {
            "total_rest_days": total,
            "weeks_analyzed": weeks,
            "by_focus": by_focus,
            "by_week": by_week
        }


@router.post("/validate-activity")
def validate_activity(
    data: ActivityConflictCheck,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """
    Check if activity conflicts with rest day configuration.

    Returns:
    - conflict: bool
    - severity: 'warning' | 'info' | 'none'
    - message: str
    """
    pid = get_pid(x_profile_id)

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute(
            """
            SELECT rest_config
            FROM rest_days
            WHERE profile_id = %s AND date = %s
            """,
            (pid, data.date)
        )

        row = cur.fetchone()
        if not row:
            return {"conflict": False, "severity": "none", "message": ""}

        config = row['rest_config']

        # Check if activity is in rest_from
        if data.activity_type in config.get('rest_from', []):
            focus_labels = {
                'muscle_recovery': 'Muskelregeneration',
                'cardio_recovery': 'Cardio-Erholung',
                'mental_rest': 'Mentale Erholung',
                'deload': 'Deload',
                'injury': 'Verletzungspause'
            }
            focus_label = focus_labels.get(config.get('focus'), 'Ruhetag')

            return {
                "conflict": True,
                "severity": "warning",
                "message": f"Ruhetag ({focus_label}) – {data.activity_type} sollte pausiert werden. Trotzdem erfassen?"
            }

        # Check if activity is allowed
        allows_list = config.get('allows', [])
        if allows_list and data.activity_type not in allows_list:
            return {
                "conflict": True,
                "severity": "info",
                "message": f"Aktivität nicht in erlaubten Aktivitäten. Heute: {', '.join(allows_list) or 'Keine'}."
            }

        # Check intensity_max (if provided in request)
        intensity_max = config.get('intensity_max')
        if intensity_max:
            return {
                "conflict": False,
                "severity": "info",
                "message": f"Erlaubt bei max. {intensity_max}% HFmax."
            }

        return {"conflict": False, "severity": "none", "message": ""}
