from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional, List
from utils.utils import get_db
from . import handler
from .schema import (
    CalculationCreate,
    CalculationUpdate,
    CalculationResponse,
    CalculationDetailsResponse,
    PaginatedResponse,
    CalculationbreakdownCreate,
    CalculationbreakdownUpdate,
    CalculationbreakdownResponse,
)

router = APIRouter(prefix="/calculations", tags=["Calculations"])


@router.post(
    "/",
    response_model=CalculationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create New SIP Calculation",
    description="Creates a new SIP calculation record with input parameters and computed results. Validates that monthly investment is between 500 and 10,000,000, investment period is between 1 and 40 years, and expected return rate is between 1% and 30%. Returns 400 if validation fails.",
)
def create_calculation_route(data: CalculationCreate, db: Session = Depends(get_db)):
    return handler.create_calculation(db, data)


@router.get(
    "/{calculation_id}",
    response_model=CalculationResponse,
    summary="Get Calculation by ID",
    description="Retrieves a single calculation record by its ID. Returns 404 if the calculation does not exist.",
)
def get_calculation_route(calculation_id: str, db: Session = Depends(get_db)):
    return handler.get_calculation(db, calculation_id)


@router.get(
    "/{calculation_id}/details",
    response_model=CalculationDetailsResponse,
    summary="Get Calculation with Full Breakdown",
    description="Retrieves a calculation record with all associated period-wise breakdowns for visualization. Eager-loads calculation_breakdowns to avoid N+1 queries. Returns 404 if the calculation does not exist.",
)
def get_calculation_details_route(calculation_id: str, db: Session = Depends(get_db)):
    return handler.get_calculation_details(db, calculation_id)


@router.get(
    "/",
    response_model=PaginatedResponse[CalculationResponse],
    summary="List Calculations",
    description="Returns a paginated list of calculation records. Supports optional session_id filter to retrieve calculations for a specific anonymous session. Default limit is 20, ordered by creation date descending.",
)
def list_calculations_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    session_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_calculations(db, limit, offset, session_id=session_id)


@router.patch(
    "/{calculation_id}",
    response_model=CalculationResponse,
    summary="Update Calculation",
    description="Updates an existing calculation record. Only provided fields are updated; unset fields remain unchanged. Returns 404 if the calculation does not exist, 400 if no fields are provided.",
)
def update_calculation_route(
    calculation_id: str,
    data: CalculationUpdate,
    db: Session = Depends(get_db),
):
    return handler.update_calculation(db, calculation_id, data)


@router.delete(
    "/{calculation_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Calculation",
    description="Deletes a calculation record and all associated breakdowns. Cascading delete is enforced via ON DELETE CASCADE. Returns 404 if the calculation does not exist.",
)
def delete_calculation_route(calculation_id: str, db: Session = Depends(get_db)):
    return handler.delete_calculation(db, calculation_id)


@router.get(
    "/{calculation_id}/breakdowns",
    response_model=List[CalculationbreakdownResponse],
    summary="List Breakdowns for Calculation",
    description="Returns all period-wise breakdowns for a given calculation, ordered by period ascending. Returns 404 if the parent calculation does not exist.",
)
def list_breakdowns_route(calculation_id: str, db: Session = Depends(get_db)):
    return handler.list_breakdowns_by_calculation(db, calculation_id)


@router.post(
    "/breakdowns",
    response_model=CalculationbreakdownResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Calculation Breakdown",
    description="Creates a new breakdown record for a calculation. Validates that the parent calculation exists. Returns 400 if the calculation_id is invalid or does not exist.",
)
def create_breakdown_route(data: CalculationbreakdownCreate, db: Session = Depends(get_db)):
    return handler.create_breakdown(db, data)


@router.get(
    "/breakdowns/{breakdown_id}",
    response_model=CalculationbreakdownResponse,
    summary="Get Breakdown by ID",
    description="Retrieves a single breakdown record by its ID. Returns 404 if the breakdown does not exist.",
)
def get_breakdown_route(breakdown_id: str, db: Session = Depends(get_db)):
    return handler.get_breakdown(db, breakdown_id)


@router.patch(
    "/breakdowns/{breakdown_id}",
    response_model=CalculationbreakdownResponse,
    summary="Update Breakdown",
    description="Updates an existing breakdown record. Only provided fields are updated; unset fields remain unchanged. Returns 404 if the breakdown does not exist, 400 if no fields are provided.",
)
def update_breakdown_route(
    breakdown_id: str,
    data: CalculationbreakdownUpdate,
    db: Session = Depends(get_db),
):
    return handler.update_breakdown(db, breakdown_id, data)


@router.delete(
    "/breakdowns/{breakdown_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Breakdown",
    description="Deletes a single breakdown record. Returns 404 if the breakdown does not exist.",
)
def delete_breakdown_route(breakdown_id: str, db: Session = Depends(get_db)):
    return handler.delete_breakdown(db, breakdown_id)