"""Scenario API endpoints."""

from uuid import UUID
from datetime import datetime
from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.deps import get_db
from src.repositories.scenario import scenario_repository, ScenarioStatus
from src.schemas.scenario import (
    ScenarioCreate,
    ScenarioUpdate,
    ScenarioResponse,
    ScenarioList,
)
from src.core.exceptions import NotFoundException, ValidationException
from src.core.config import settings

router = APIRouter()


@router.post("", response_model=ScenarioResponse, status_code=status.HTTP_201_CREATED)
async def create_scenario(
    scenario_in: ScenarioCreate, db: AsyncSession = Depends(get_db)
):
    """Create a new scenario."""
    existing = await scenario_repository.get_by_name(db, scenario_in.name)
    if existing:
        raise ValidationException(
            f"Scenario with name '{scenario_in.name}' already exists"
        )

    scenario = await scenario_repository.create(db, obj_in=scenario_in.model_dump())
    return scenario


@router.get("", response_model=ScenarioList)
async def list_scenarios(
    status: str = Query(None, description="Filter by status"),
    region: str = Query(None, description="Filter by region"),
    page: int = Query(1, ge=1, description="Page number"),
    page_size: int = Query(
        settings.default_page_size,
        ge=1,
        le=settings.max_page_size,
        description="Items per page",
    ),
    db: AsyncSession = Depends(get_db),
):
    """List scenarios with optional filtering."""
    skip = (page - 1) * page_size

    filters = {}
    if status:
        filters["status"] = status
    if region:
        filters["region"] = region

    scenarios = await scenario_repository.get_multi(
        db, skip=skip, limit=page_size, **filters
    )
    total = await scenario_repository.count(db, **filters)

    return ScenarioList(items=scenarios, total=total, page=page, page_size=page_size)


@router.get("/{scenario_id}", response_model=ScenarioResponse)
async def get_scenario(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Get a specific scenario by ID."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")
    return scenario


@router.put("/{scenario_id}", response_model=ScenarioResponse)
async def update_scenario(
    scenario_id: UUID, scenario_in: ScenarioUpdate, db: AsyncSession = Depends(get_db)
):
    """Update a scenario."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    if scenario_in.name and scenario_in.name != scenario.name:
        existing = await scenario_repository.get_by_name(db, scenario_in.name)
        if existing:
            raise ValidationException(
                f"Scenario with name '{scenario_in.name}' already exists"
            )

    updated = await scenario_repository.update(
        db, db_obj=scenario, obj_in=scenario_in.model_dump(exclude_unset=True)
    )
    return updated


@router.delete("/{scenario_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_scenario(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Delete a scenario."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    await scenario_repository.delete(db, id=scenario_id)
    return None


@router.post("/{scenario_id}/start", response_model=ScenarioResponse)
async def start_scenario(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Start a scenario (draft -> running)."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    if scenario.status != ScenarioStatus.DRAFT.value:
        raise ValidationException(
            f"Cannot start scenario with status '{scenario.status}'"
        )

    await scenario_repository.update(
        db,
        db_obj=scenario,
        obj_in={
            "status": ScenarioStatus.RUNNING.value,
            "started_at": datetime.utcnow(),
        },
    )
    await db.refresh(scenario)
    return scenario


@router.post("/{scenario_id}/stop", response_model=ScenarioResponse)
async def stop_scenario(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Stop a scenario (running -> completed)."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    if scenario.status != ScenarioStatus.RUNNING.value:
        raise ValidationException(
            f"Cannot stop scenario with status '{scenario.status}'"
        )

    await scenario_repository.update(
        db,
        db_obj=scenario,
        obj_in={
            "status": ScenarioStatus.COMPLETED.value,
            "completed_at": datetime.utcnow(),
        },
    )
    await db.refresh(scenario)
    return scenario


@router.post("/{scenario_id}/archive", response_model=ScenarioResponse)
async def archive_scenario(scenario_id: UUID, db: AsyncSession = Depends(get_db)):
    """Archive a scenario (completed -> archived)."""
    scenario = await scenario_repository.get(db, scenario_id)
    if not scenario:
        raise NotFoundException("Scenario")

    if scenario.status != ScenarioStatus.COMPLETED.value:
        raise ValidationException(
            f"Cannot archive scenario with status '{scenario.status}'"
        )

    await scenario_repository.update_status(db, scenario_id, ScenarioStatus.ARCHIVED)
    await db.refresh(scenario)
    return scenario
