"""CSV upload and ingest API routes."""

import uuid
from pathlib import Path

import pandas as pd
from fastapi import APIRouter, Depends, HTTPException, UploadFile, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from mixlift.config import settings
from mixlift.deps import get_current_user, get_db
from mixlift.ingest.service import detect_platform, parse_csv, save_as_parquet, validate_data
from mixlift.projects.models import Dataset, Project, User
from mixlift.projects.schemas import DatasetResponse

router = APIRouter(tags=["ingest"])


@router.post(
    "/projects/{project_id}/upload",
    response_model=DatasetResponse,
    status_code=status.HTTP_201_CREATED,
)
async def upload_csv(
    project_id: str,
    file: UploadFile,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
):
    # Verify project ownership
    result = await session.execute(
        select(Project).where(Project.id == project_id, Project.user_id == user.id)
    )
    project = result.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")

    # Read CSV
    try:
        raw_df = pd.read_csv(file.file)
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Could not parse CSV: {e}",
        )

    # Tier-based row limit
    if user.tier == "free" and len(raw_df) > settings.free_max_rows:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=f"Free tier limited to {settings.free_max_rows} rows. "
            f"Your file has {len(raw_df)} rows.",
        )

    # Detect platform and parse
    platform = detect_platform(raw_df)
    try:
        canonical, _ = parse_csv(raw_df, platform)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))

    # Validate
    errors = validate_data(canonical)
    if errors:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail={"validation_errors": errors},
        )

    # Channel limit for free tier
    n_channels = canonical["channel"].nunique()
    if user.tier == "free" and n_channels > settings.free_max_channels:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=f"Free tier limited to {settings.free_max_channels} channels. "
            f"Found {n_channels}.",
        )

    # Save as parquet
    dataset_id = str(uuid.uuid4())
    storage_path = str(settings.upload_dir / f"{dataset_id}.parquet")
    save_as_parquet(canonical, storage_path)

    # Deactivate previous datasets for this project
    prev_datasets = await session.execute(
        select(Dataset).where(Dataset.project_id == project.id, Dataset.is_active.is_(True))
    )
    for ds in prev_datasets.scalars():
        ds.is_active = False

    # Create dataset record
    channels = canonical["channel"].unique().tolist()
    dataset = Dataset(
        id=dataset_id,
        project_id=project.id,
        filename=file.filename or "upload.csv",
        platform=platform,
        row_count=len(canonical),
        date_range_start=canonical["date"].min(),
        date_range_end=canonical["date"].max(),
        channel_columns={"channels": channels},
        target_column=project.target_metric,
        storage_path=storage_path,
    )
    session.add(dataset)
    await session.flush()

    return DatasetResponse(
        id=str(dataset.id),
        filename=dataset.filename,
        platform=dataset.platform,
        row_count=dataset.row_count,
        date_range_start=dataset.date_range_start,
        date_range_end=dataset.date_range_end,
        channel_columns=dataset.channel_columns,
        is_active=dataset.is_active,
        created_at=dataset.created_at,
    )


@router.get("/projects/{project_id}/data/preview")
async def preview_data(
    project_id: str,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
):
    result = await session.execute(
        select(Project).where(Project.id == project_id, Project.user_id == user.id)
    )
    if not result.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")

    ds_result = await session.execute(
        select(Dataset)
        .where(Dataset.project_id == project_id, Dataset.is_active.is_(True))
        .order_by(Dataset.created_at.desc())
        .limit(1)
    )
    dataset = ds_result.scalar_one_or_none()
    if not dataset:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="No active dataset")

    df = pd.read_parquet(dataset.storage_path)
    preview = df.head(50).to_dict(orient="records")

    return {
        "filename": dataset.filename,
        "platform": dataset.platform,
        "row_count": dataset.row_count,
        "channels": dataset.channel_columns.get("channels", []) if dataset.channel_columns else [],
        "date_range": {
            "start": str(dataset.date_range_start),
            "end": str(dataset.date_range_end),
        },
        "preview": preview,
    }
