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 (
    LoancalculationCreate,
    LoancalculationUpdate,
    LoancalculationResponse,
    LoancalculationWithScheduleResponse,
    LoanCalculationInput,
    AmortizationscheduleentryCreate,
    AmortizationscheduleentryUpdate,
    AmortizationscheduleentryResponse,
)

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


@router.post(
    "/",
    response_model=LoancalculationResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Loan Calculation",
    description="Creates a new loan calculation record with computed monthly payment, total interest, and total amount. Validates that principal is positive, interest rate is between 0 and 100, and loan term is between 1 and 600 months.",
)
def create_loan_calculation_route(data: LoancalculationCreate, db: Session = Depends(get_db)):
    return handler.create_loan_calculation(db, data)


@router.get(
    "/",
    response_model=List[LoancalculationResponse],
    summary="List Loan Calculations",
    description="Returns a paginated list of loan calculations. Supports optional filtering by session_id to retrieve calculations for a specific user session.",
)
def list_loan_calculations_route(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    session_id: Optional[str] = None,
    db: Session = Depends(get_db),
):
    return handler.list_loan_calculations(db, limit, offset, session_id)


@router.get(
    "/{id}",
    response_model=LoancalculationResponse,
    summary="Get Loan Calculation",
    description="Retrieves a single loan calculation by ID. Returns 404 if the calculation does not exist.",
)
def get_loan_calculation_route(id: str, db: Session = Depends(get_db)):
    return handler.get_loan_calculation(db, id)


@router.put(
    "/{id}",
    response_model=LoancalculationResponse,
    summary="Update Loan Calculation",
    description="Updates an existing loan calculation. Only provided fields are updated. Returns 404 if the calculation does not exist.",
)
def update_loan_calculation_route(id: str, data: LoancalculationUpdate, db: Session = Depends(get_db)):
    return handler.update_loan_calculation(db, id, data)


@router.delete(
    "/{id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete Loan Calculation",
    description="Deletes a loan calculation and all associated amortization schedule entries. Returns 404 if the calculation does not exist.",
)
def delete_loan_calculation_route(id: str, db: Session = Depends(get_db)):
    handler.delete_loan_calculation(db, id)


@router.get(
    "/{id}/details",
    response_model=LoancalculationWithScheduleResponse,
    summary="Get Loan Calculation With Schedule",
    description="Retrieves a loan calculation with its complete amortization schedule. Returns all schedule entries with payment breakdowns including principal, interest, and cumulative totals. Returns 404 if the calculation does not exist.",
)
def get_loan_calculation_with_schedule_route(id: str, db: Session = Depends(get_db)):
    return handler.get_loan_calculation_with_schedule(db, id)


@router.post(
    "/calculate",
    response_model=LoancalculationWithScheduleResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Calculate Loan With Schedule",
    description="Performs a complete loan calculation including monthly payment computation and full amortization schedule generation. Uses standard amortization formula for non-zero interest rates. For 0% interest, monthly payment equals principal divided by term. Creates loan calculation record and all schedule entries in a single transaction. Returns 400 if validation fails.",
)
def calculate_loan_route(data: LoanCalculationInput, db: Session = Depends(get_db)):
    return handler.calculate_loan(db, data)


@router.get(
    "/{id}/amortization-schedule",
    response_model=List[AmortizationscheduleentryResponse],
    summary="Get Amortization Schedule",
    description="Retrieves the complete amortization schedule for a loan calculation. Returns all payment periods with beginning balance, payment amount, principal portion, interest portion, ending balance, and cumulative totals. Returns 404 if the loan calculation does not exist.",
)
def get_amortization_schedule_route(
    id: str,
    limit: int = Query(600, ge=1, le=600),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    return handler.list_schedule_entries(db, id, limit, offset)


@router.post(
    "/schedule-entries",
    response_model=AmortizationscheduleentryResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Schedule Entry",
    description="Creates a new amortization schedule entry. Validates that the referenced loan calculation exists. Returns 404 if the loan calculation is not found.",
)
def create_schedule_entry_route(data: AmortizationscheduleentryCreate, db: Session = Depends(get_db)):
    return handler.create_schedule_entry(db, data)


@router.get(
    "/schedule-entries/{entry_id}",
    response_model=AmortizationscheduleentryResponse,
    summary="Get Schedule Entry",
    description="Retrieves a single amortization schedule entry by ID. Returns 404 if the entry does not exist.",
)
def get_schedule_entry_route(entry_id: str, db: Session = Depends(get_db)):
    return handler.get_schedule_entry(db, entry_id)


@router.put(
    "/schedule-entries/{entry_id}",
    response_model=AmortizationscheduleentryResponse,
    summary="Update Schedule Entry",
    description="Updates an existing amortization schedule entry. Only provided fields are updated. Returns 404 if the entry does not exist.",
)
def update_schedule_entry_route(entry_id: str, data: AmortizationscheduleentryUpdate, db: Session = Depends(get_db)):
    return handler.update_schedule_entry(db, entry_id, data)


@router.delete(
    "/schedule-entries/{entry_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete Schedule Entry",
    description="Deletes an amortization schedule entry. Returns 404 if the entry does not exist.",
)
def delete_schedule_entry_route(entry_id: str, db: Session = Depends(get_db)):
    handler.delete_schedule_entry(db, entry_id)