from __future__ import annotations

from typing import Annotated

from fastapi import APIRouter, Path, Query, Request

from backend.data.gateway import MarketDataUnavailable
from backend.data.providers.base import ProviderError
from backend.features.accounts.auth import (
    AdminPrincipal,
    AdminWritePrincipal,
    AuthenticatedPrincipal,
)
from backend.features.market.events import MarketEventError
from backend.features.operations.schemas import (
    BackfillInput,
    EventRevisionInput,
    JobRunResponse,
    OperationResult,
    RuntimeStatusResponse,
)
from backend.features.operations.service import OperationsError
from backend.http.errors import AppError

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


@router.get("/operations/status", response_model=RuntimeStatusResponse)
def public_status(request: Request, _principal: AuthenticatedPrincipal) -> dict:
    return request.app.state.container.operations.public_status()


@router.get("/admin/operations/jobs", response_model=list[JobRunResponse])
def jobs(request: Request, _principal: AdminPrincipal) -> list[dict]:
    return request.app.state.container.operations.jobs()


@router.post("/admin/operations/backfill", response_model=OperationResult)
def backfill(
    payload: BackfillInput, request: Request, _principal: AdminWritePrincipal
) -> dict:
    try:
        return request.app.state.container.operations.backfill(
            payload.start_date.isoformat(), payload.end_date.isoformat()
        )
    except OperationsError as exc:
        raise AppError("invalid_operation", str(exc), 400) from exc


@router.post("/admin/operations/events/supplement", response_model=OperationResult)
def supplement_events(
    request: Request,
    _principal: AdminWritePrincipal,
    trade_date: Annotated[str, Query(alias="date")],
) -> dict:
    try:
        return request.app.state.container.operations.supplement_events(trade_date)
    except (OperationsError, MarketEventError) as exc:
        raise AppError("invalid_operation", str(exc), 400) from exc
    except (MarketDataUnavailable, ProviderError) as exc:
        raise AppError("event_service_unavailable", str(exc), 503) from exc


@router.put(
    "/admin/operations/events/{trade_date}/{identifier}",
    response_model=OperationResult,
)
def revise_event(
    payload: EventRevisionInput,
    request: Request,
    principal: AdminWritePrincipal,
    trade_date: Annotated[str, Path()],
    identifier: Annotated[str, Path(min_length=1, max_length=20)],
) -> dict:
    try:
        return request.app.state.container.operations.revise_event(
            principal.user.id,
            trade_date=trade_date,
            identifier=identifier,
            **payload.model_dump(),
        )
    except (OperationsError, MarketEventError) as exc:
        raise AppError("invalid_event_revision", str(exc), 400) from exc


@router.get(
    "/admin/operations/events/{trade_date}/{identifier}/history",
    response_model=list[OperationResult],
)
def event_history(
    request: Request,
    _principal: AdminPrincipal,
    trade_date: Annotated[str, Path()],
    identifier: Annotated[str, Path(min_length=1, max_length=20)],
) -> list[dict]:
    return request.app.state.container.operations.event_history(trade_date, identifier)
