from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional
from decimal import Decimal
from datetime import datetime
from utils.utils import get_db
from . import handler
from .schema import (
    CalculationsettingsCreate,
    CalculationsettingsUpdate,
    CalculationsettingsResponse,
    PaginatedResponse,
    LoancalculationCreate,
    LoancalculationUpdate,
    LoancalculationResponse,
    LoancalculationDetailResponse,
    AmortizationentryCreate,
    AmortizationentryUpdate,
    AmortizationentryResponse,
    AmortizationentrySummary,
)

router = APIRouter(prefix="/calculation-management", tags=["Calculation Management"])


# CalculationSettings routes
@router.post(
    "/calculation-settings",
    response_model=CalculationsettingsResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Calculation Settings",
    description="Creates new calculation settings with default values and display preferences. Returns 409 if settings_id already exists.",
)
def create_calculationsettings_route(
    data: CalculationsettingsCreate,
    db: Session = Depends(get_db),
):
    return handler.create_calculationsettings(db, data)


@router.get(
    "/calculation-settings/{entity_id}",
    response_model=CalculationsettingsResponse,
    summary="Get Calculation Settings by ID",
    description="Retrieves calculation settings by UUID. Returns 404 if not found.",
)
def get_calculationsettings_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.get_calculationsettings_by_id(db, entity_id)


@router.get(
    "/calculation-settings/default/current",
    response_model=CalculationsettingsResponse,
    summary="Get Default Calculation Settings",
    description="Retrieves the default calculation settings for the loan calculator. Returns the first available settings record.",
)
def get_default_calculationsettings_route(
    db: Session = Depends(get_db),
):
    return handler.get_default_calculationsettings(db)


@router.get(
    "/calculation-settings",
    response_model=PaginatedResponse[CalculationsettingsResponse],
    summary="List Calculation Settings",
    description="Returns a paginated list of all calculation settings records.",
)
def list_calculationsettings_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    return handler.list_calculationsettings(db, limit, offset)


@router.put(
    "/calculation-settings/{entity_id}",
    response_model=CalculationsettingsResponse,
    summary="Update Calculation Settings",
    description="Updates an existing calculation settings record. Returns 404 if not found, 409 if new settings_id conflicts with existing record.",
)
def update_calculationsettings_route(
    entity_id: str,
    data: CalculationsettingsUpdate,
    db: Session = Depends(get_db),
):
    return handler.update_calculationsettings(db, entity_id, data)


@router.delete(
    "/calculation-settings/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Calculation Settings",
    description="Deletes a calculation settings record. Returns 404 if not found, 409 if still referenced by loan calculations.",
)
def delete_calculationsettings_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.delete_calculationsettings(db, entity_id)


# LoanCalculation routes
@router.post(
    "/loan-calculations",
    response_model=LoancalculationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Loan Calculation",
    description="Creates a new loan calculation record with all computed fields. Returns 409 if calculation_id already exists.",
)
def create_loancalculation_route(
    data: LoancalculationCreate,
    db: Session = Depends(get_db),
):
    return handler.create_loancalculation(db, data)


@router.get(
    "/loan-calculations/{entity_id}",
    response_model=LoancalculationResponse,
    summary="Get Loan Calculation by ID",
    description="Retrieves a loan calculation by UUID. Returns 404 if not found.",
)
def get_loancalculation_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.get_loancalculation_by_id(db, entity_id)


@router.get(
    "/loan-calculations/{entity_id}/details",
    response_model=LoancalculationDetailResponse,
    summary="Get Loan Calculation Details",
    description="Retrieves loan calculation with associated settings and full amortization schedule. Returns 404 if not found.",
)
def get_loancalculation_details_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.get_loancalculation_details(db, entity_id)


@router.get(
    "/loan-calculations",
    response_model=PaginatedResponse[LoancalculationResponse],
    summary="List Loan Calculations",
    description="Returns a paginated list of loan calculations with optional filtering by calculation_id or settings_id.",
)
def list_loancalculations_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    calculation_id: Optional[str] = None,
    settings_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if calculation_id:
        filters["calculation_id"] = calculation_id
    if settings_id:
        filters["settings_id"] = settings_id
    return handler.list_loancalculations(db, limit, offset, **filters)


@router.put(
    "/loan-calculations/{entity_id}",
    response_model=LoancalculationResponse,
    summary="Update Loan Calculation",
    description="Updates an existing loan calculation. Returns 404 if not found, 409 if new calculation_id conflicts.",
)
def update_loancalculation_route(
    entity_id: str,
    data: LoancalculationUpdate,
    db: Session = Depends(get_db),
):
    return handler.update_loancalculation(db, entity_id, data)


@router.delete(
    "/loan-calculations/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Loan Calculation",
    description="Deletes a loan calculation and all associated amortization entries. Returns 404 if not found.",
)
def delete_loancalculation_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.delete_loancalculation(db, entity_id)


@router.post(
    "/loan-calculations/calculate",
    response_model=LoancalculationDetailResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Calculate Loan with Amortization Schedule",
    description="Performs complete loan calculation including monthly payment, total interest, and generates full amortization schedule with one entry per month. Validates all inputs against business rules. Returns 400 for invalid inputs, 409 if calculation_id already exists.",
)
def calculate_loan_route(
    calculation_id: str,
    principal_amount: Decimal = Query(..., ge=Decimal("100"), le=Decimal("100000000")),
    annual_interest_rate: Decimal = Query(..., ge=Decimal("0.01"), le=Decimal("99.99")),
    loan_term_months: int = Query(..., ge=1, le=480),
    settings_id: Optional[str] = None,
    start_date: Optional[datetime] = None,
    db: Session = Depends(get_db),
):
    return handler.calculate_loan_service(
        db,
        calculation_id,
        principal_amount,
        annual_interest_rate,
        loan_term_months,
        settings_id,
        start_date,
    )


@router.get(
    "/loan-calculations/{calculation_id}/amortization-schedule",
    response_model=list[AmortizationentrySummary],
    summary="Get Amortization Schedule",
    description="Retrieves the complete amortization schedule for a loan calculation, showing payment breakdown for each month. Returns 404 if calculation not found.",
)
def get_amortization_schedule_route(
    calculation_id: str,
    db: Session = Depends(get_db),
):
    return handler.get_amortization_schedule(db, calculation_id)


# AmortizationEntry routes
@router.post(
    "/amortization-entries",
    response_model=AmortizationentryResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Amortization Entry",
    description="Creates a new amortization entry for a loan calculation. Returns 409 if entry_id already exists, 400 if referenced calculation does not exist.",
)
def create_amortizationentry_route(
    data: AmortizationentryCreate,
    db: Session = Depends(get_db),
):
    return handler.create_amortizationentry(db, data)


@router.get(
    "/amortization-entries/{entity_id}",
    response_model=AmortizationentryResponse,
    summary="Get Amortization Entry by ID",
    description="Retrieves an amortization entry by UUID. Returns 404 if not found.",
)
def get_amortizationentry_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.get_amortizationentry_by_id(db, entity_id)


@router.get(
    "/amortization-entries",
    response_model=PaginatedResponse[AmortizationentryResponse],
    summary="List Amortization Entries",
    description="Returns a paginated list of amortization entries with optional filtering by calculation_id.",
)
def list_amortizationentries_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    calculation_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    filters = {}
    if calculation_id:
        filters["calculation_id"] = calculation_id
    return handler.list_amortizationentries(db, limit, offset, **filters)


@router.put(
    "/amortization-entries/{entity_id}",
    response_model=AmortizationentryResponse,
    summary="Update Amortization Entry",
    description="Updates an existing amortization entry. Returns 404 if not found, 409 if new entry_id conflicts.",
)
def update_amortizationentry_route(
    entity_id: str,
    data: AmortizationentryUpdate,
    db: Session = Depends(get_db),
):
    return handler.update_amortizationentry(db, entity_id, data)


@router.delete(
    "/amortization-entries/{entity_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Amortization Entry",
    description="Deletes an amortization entry. Returns 404 if not found.",
)
def delete_amortizationentry_route(
    entity_id: str,
    db: Session = Depends(get_db),
):
    return handler.delete_amortizationentry(db, entity_id)