"""
Vitals Baseline Router - v9d Phase 2d Refactored

Baseline vitals measured once daily (morning, fasted):
- Resting Heart Rate (RHR)
- Heart Rate Variability (HRV)
- VO2 Max
- SpO2 (Blood Oxygen Saturation)
- Respiratory Rate

Endpoints:
- GET    /api/vitals/baseline           List baseline vitals
- GET    /api/vitals/baseline/by-date/{date}  Get entry for specific date
- POST   /api/vitals/baseline           Create/update baseline entry (upsert)
- PUT    /api/vitals/baseline/{id}      Update baseline entry
- DELETE /api/vitals/baseline/{id}      Delete baseline entry
- GET    /api/vitals/baseline/stats     Statistics and trends
- POST   /api/vitals/baseline/import/apple-health  Import Apple Health CSV
"""
from fastapi import APIRouter, HTTPException, Depends, Header, UploadFile, File
from pydantic import BaseModel
from typing import Optional
from datetime import datetime, timedelta
import logging
import csv
import io

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

router = APIRouter(prefix="/api/vitals/baseline", tags=["vitals_baseline"])
logger = logging.getLogger(__name__)


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Pydantic Models
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class BaselineEntry(BaseModel):
    date: str
    resting_hr: Optional[int] = None
    hrv: Optional[int] = None
    vo2_max: Optional[float] = None
    spo2: Optional[int] = None
    respiratory_rate: Optional[float] = None
    body_temperature: Optional[float] = None
    resting_metabolic_rate: Optional[int] = None
    note: Optional[str] = None


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# CRUD Endpoints
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

@router.get("")
def list_baseline_vitals(
    limit: int = 90,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Get baseline vitals (last N days)."""
    pid = get_pid(x_profile_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("""
            SELECT * FROM vitals_baseline
            WHERE profile_id = %s
            ORDER BY date DESC
            LIMIT %s
        """, (pid, limit))
        return [r2d(r) for r in cur.fetchall()]


@router.get("/by-date/{date}")
def get_baseline_by_date(
    date: str,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Get baseline entry for specific date."""
    pid = get_pid(x_profile_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("""
            SELECT * FROM vitals_baseline
            WHERE profile_id = %s AND date = %s
        """, (pid, date))
        row = cur.fetchone()
        return r2d(row) if row else None


@router.post("")
def create_or_update_baseline(
    entry: BaselineEntry,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Create or update baseline entry (upsert on date)."""
    pid = get_pid(x_profile_id)

    # Build dynamic INSERT columns, placeholders, UPDATE fields, and values list
    # All arrays must stay synchronized
    insert_cols = []
    insert_placeholders = []
    update_fields = []
    param_values = []  # Will contain ALL values including pid and date

    # Always include profile_id and date
    param_values.append(pid)
    param_values.append(entry.date)

    if entry.resting_hr is not None:
        insert_cols.append("resting_hr")
        insert_placeholders.append("%s")
        update_fields.append("resting_hr = EXCLUDED.resting_hr")
        param_values.append(entry.resting_hr)

    if entry.hrv is not None:
        insert_cols.append("hrv")
        insert_placeholders.append("%s")
        update_fields.append("hrv = EXCLUDED.hrv")
        param_values.append(entry.hrv)

    if entry.vo2_max is not None:
        insert_cols.append("vo2_max")
        insert_placeholders.append("%s")
        update_fields.append("vo2_max = EXCLUDED.vo2_max")
        param_values.append(entry.vo2_max)

    if entry.spo2 is not None:
        insert_cols.append("spo2")
        insert_placeholders.append("%s")
        update_fields.append("spo2 = EXCLUDED.spo2")
        param_values.append(entry.spo2)

    if entry.respiratory_rate is not None:
        insert_cols.append("respiratory_rate")
        insert_placeholders.append("%s")
        update_fields.append("respiratory_rate = EXCLUDED.respiratory_rate")
        param_values.append(entry.respiratory_rate)

    if entry.body_temperature is not None:
        insert_cols.append("body_temperature")
        insert_placeholders.append("%s")
        update_fields.append("body_temperature = EXCLUDED.body_temperature")
        param_values.append(entry.body_temperature)

    if entry.resting_metabolic_rate is not None:
        insert_cols.append("resting_metabolic_rate")
        insert_placeholders.append("%s")
        update_fields.append("resting_metabolic_rate = EXCLUDED.resting_metabolic_rate")
        param_values.append(entry.resting_metabolic_rate)

    if entry.note:
        insert_cols.append("note")
        insert_placeholders.append("%s")
        update_fields.append("note = EXCLUDED.note")
        param_values.append(entry.note)

    # At least one field must be provided
    if not insert_cols:
        raise HTTPException(400, "At least one baseline vital must be provided")

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

        # Build complete column list and placeholder list
        # IMPORTANT: psycopg2 uses %s placeholders, NOT $1/$2/$3
        all_cols = f"profile_id, date, {', '.join(insert_cols)}"
        all_placeholders = f"%s, %s, {', '.join(insert_placeholders)}"

        query = f"""
            INSERT INTO vitals_baseline ({all_cols})
            VALUES ({all_placeholders})
            ON CONFLICT (profile_id, date)
            DO UPDATE SET {', '.join(update_fields)}, updated_at = NOW()
            RETURNING *
        """

        # Debug logging
        print(f"[DEBUG] Vitals baseline query: {query}")
        print(f"[DEBUG] Param values ({len(param_values)}): {param_values}")

        cur.execute(query, tuple(param_values))
        return r2d(cur.fetchone())


@router.put("/{entry_id}")
def update_baseline(
    entry_id: int,
    entry: BaselineEntry,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Update existing baseline entry."""
    pid = get_pid(x_profile_id)

    # Build SET clause dynamically
    updates = []
    values = []

    if entry.resting_hr is not None:
        updates.append("resting_hr = %s")
        values.append(entry.resting_hr)
    if entry.hrv is not None:
        updates.append("hrv = %s")
        values.append(entry.hrv)
    if entry.vo2_max is not None:
        updates.append("vo2_max = %s")
        values.append(entry.vo2_max)
    if entry.spo2 is not None:
        updates.append("spo2 = %s")
        values.append(entry.spo2)
    if entry.respiratory_rate is not None:
        updates.append("respiratory_rate = %s")
        values.append(entry.respiratory_rate)
    if entry.body_temperature is not None:
        updates.append("body_temperature = %s")
        values.append(entry.body_temperature)
    if entry.resting_metabolic_rate is not None:
        updates.append("resting_metabolic_rate = %s")
        values.append(entry.resting_metabolic_rate)
    if entry.note:
        updates.append("note = %s")
        values.append(entry.note)

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

    updates.append("updated_at = NOW()")
    values.extend([entry_id, pid])

    with get_db() as conn:
        cur = get_cursor(conn)
        query = f"""
            UPDATE vitals_baseline
            SET {', '.join(updates)}
            WHERE id = %s AND profile_id = %s
            RETURNING *
        """
        cur.execute(query, values)
        row = cur.fetchone()
        if not row:
            raise HTTPException(404, "Entry not found")
        return r2d(row)


@router.delete("/{entry_id}")
def delete_baseline(
    entry_id: int,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Delete baseline entry."""
    pid = get_pid(x_profile_id)
    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("""
            DELETE FROM vitals_baseline
            WHERE id = %s AND profile_id = %s
        """, (entry_id, pid))
        if cur.rowcount == 0:
            raise HTTPException(404, "Entry not found")
        return {"ok": True}


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Statistics & Trends
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

@router.get("/stats")
def get_baseline_stats(
    days: int = 30,
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Get baseline vitals statistics and trends."""
    pid = get_pid(x_profile_id)
    cutoff_date = (datetime.now() - timedelta(days=days)).date()

    with get_db() as conn:
        cur = get_cursor(conn)
        cur.execute("""
            SELECT
                COUNT(*) as total_entries,
                -- Resting HR
                AVG(resting_hr) FILTER (WHERE date >= %s - INTERVAL '7 days') as avg_rhr_7d,
                AVG(resting_hr) FILTER (WHERE date >= %s - INTERVAL '30 days') as avg_rhr_30d,
                -- HRV
                AVG(hrv) FILTER (WHERE date >= %s - INTERVAL '7 days') as avg_hrv_7d,
                AVG(hrv) FILTER (WHERE date >= %s - INTERVAL '30 days') as avg_hrv_30d,
                -- Latest values
                (SELECT vo2_max FROM vitals_baseline WHERE profile_id = %s AND vo2_max IS NOT NULL ORDER BY date DESC LIMIT 1) as latest_vo2_max,
                AVG(spo2) FILTER (WHERE date >= %s - INTERVAL '7 days') as avg_spo2_7d
            FROM vitals_baseline
            WHERE profile_id = %s AND date >= %s
        """, (cutoff_date, cutoff_date, cutoff_date, cutoff_date, pid, cutoff_date, pid, cutoff_date))

        stats = r2d(cur.fetchone())

        # Calculate trends (7d vs 30d)
        if stats['avg_rhr_7d'] and stats['avg_rhr_30d']:
            if stats['avg_rhr_7d'] < stats['avg_rhr_30d'] - 2:
                stats['trend_rhr'] = 'decreasing'  # Good!
            elif stats['avg_rhr_7d'] > stats['avg_rhr_30d'] + 2:
                stats['trend_rhr'] = 'increasing'  # Warning
            else:
                stats['trend_rhr'] = 'stable'
        else:
            stats['trend_rhr'] = None

        if stats['avg_hrv_7d'] and stats['avg_hrv_30d']:
            if stats['avg_hrv_7d'] > stats['avg_hrv_30d'] + 5:
                stats['trend_hrv'] = 'increasing'  # Good!
            elif stats['avg_hrv_7d'] < stats['avg_hrv_30d'] - 5:
                stats['trend_hrv'] = 'decreasing'  # Warning
            else:
                stats['trend_hrv'] = 'stable'
        else:
            stats['trend_hrv'] = None

        return stats


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Import: Apple Health CSV
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

def safe_int(value):
    """Safely parse string to int, handling decimals."""
    if not value or value == '':
        return None
    try:
        # If it has a decimal point, parse as float first then round to int
        if '.' in str(value):
            return int(float(value))
        return int(value)
    except (ValueError, TypeError):
        return None

def safe_float(value):
    """Safely parse string to float."""
    if not value or value == '':
        return None
    try:
        return float(value)
    except (ValueError, TypeError):
        return None

@router.post("/import/apple-health")
async def import_apple_health_baseline(
    file: UploadFile = File(...),
    x_profile_id: Optional[str] = Header(default=None),
    session: dict = Depends(require_auth)
):
    """Import baseline vitals from Apple Health CSV export."""
    pid = get_pid(x_profile_id)

    content = await file.read()
    decoded = content.decode('utf-8')
    reader = csv.DictReader(io.StringIO(decoded))

    inserted = 0
    updated = 0
    skipped = 0
    errors = 0
    error_details = []  # Collect error messages

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

        # Log available columns for debugging
        first_row = True

        for row in reader:
            try:
                if first_row:
                    logger.info(f"CSV Columns: {list(row.keys())}")
                    first_row = False

                # Support both English and German column names
                date_raw = row.get('Start') or row.get('Datum/Uhrzeit')
                date = date_raw[:10] if date_raw else None
                if not date:
                    logger.warning(f"Skipped row (no date): Start='{row.get('Start')}', Datum/Uhrzeit='{row.get('Datum/Uhrzeit')}'")
                    skipped += 1
                    continue

                # Extract baseline vitals (support English + German column names)
                rhr = row.get('Resting Heart Rate') or row.get('Ruhepuls (count/min)')
                hrv = row.get('Heart Rate Variability') or row.get('Herzfrequenzvariabilität (ms)')
                vo2 = row.get('VO2 Max') or row.get('VO2 max (ml/(kg·min))')
                spo2 = row.get('Oxygen Saturation') or row.get('Blutsauerstoffsättigung (%)')
                resp_rate = row.get('Respiratory Rate') or row.get('Atemfrequenz (count/min)')

                # Skip if no baseline vitals
                if not any([rhr, hrv, vo2, spo2, resp_rate]):
                    logger.warning(f"Skipped row {date} (no vitals): RHR={rhr}, HRV={hrv}, VO2={vo2}, SpO2={spo2}, RespRate={resp_rate}")
                    skipped += 1
                    continue

                # Upsert
                cur.execute("""
                    INSERT INTO vitals_baseline (
                        profile_id, date,
                        resting_hr, hrv, vo2_max, spo2, respiratory_rate,
                        source
                    ) VALUES (%s, %s, %s, %s, %s, %s, %s, 'apple_health')
                    ON CONFLICT (profile_id, date)
                    DO UPDATE SET
                        resting_hr = COALESCE(EXCLUDED.resting_hr, vitals_baseline.resting_hr),
                        hrv = COALESCE(EXCLUDED.hrv, vitals_baseline.hrv),
                        vo2_max = COALESCE(EXCLUDED.vo2_max, vitals_baseline.vo2_max),
                        spo2 = COALESCE(EXCLUDED.spo2, vitals_baseline.spo2),
                        respiratory_rate = COALESCE(EXCLUDED.respiratory_rate, vitals_baseline.respiratory_rate),
                        updated_at = NOW()
                    WHERE vitals_baseline.source != 'manual'
                    RETURNING (xmax = 0) AS inserted
                """, (
                    pid, date,
                    safe_int(rhr),
                    safe_int(hrv),
                    safe_float(vo2),
                    safe_int(spo2),
                    safe_float(resp_rate)
                ))

                result = cur.fetchone()
                if result is None:
                    # WHERE clause prevented update (manual entry exists)
                    skipped += 1
                elif result['inserted']:
                    inserted += 1
                else:
                    updated += 1

            except Exception as e:
                import traceback
                error_msg = f"Row {date if 'date' in locals() else 'unknown'}: {str(e)}"
                error_details.append(error_msg)
                logger.error(f"{error_msg}\n{traceback.format_exc()}")
                errors += 1

    return {
        "inserted": inserted,
        "updated": updated,
        "skipped": skipped,
        "errors": errors,
        "error_details": error_details[:10]  # Return first 10 errors
    }
