from typing import List, Optional
from fastapi import APIRouter, Depends, status
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.models.employee import Employee
from app.models.loan import Loan
from app.models.loan_transaction import LoanTransaction
from app.schemas.loan import (
    LoanCreate,
    LoanUpdate,
    LoanOut,
    LoanTransactionCreate,
    LoanTransactionOut,
    CombinedLedgerRow,
)
from app.helpers.crud import get_or_404

router = APIRouter(prefix="/api", tags=["loans"])


# ── Per-employee loan list ─────────────────────────────────────────────────────

@router.get("/employees/{employee_id}/loans", response_model=List[LoanOut])
def get_employee_loans(employee_id: str, db: Session = Depends(get_db)):
    get_or_404(db, Employee, employee_id, "Employee")
    return (
        db.query(Loan)
        .filter(Loan.employee_id == employee_id)
        .order_by(Loan.loan_date)
        .all()
    )


@router.post(
    "/employees/{employee_id}/loans",
    response_model=LoanOut,
    status_code=status.HTTP_201_CREATED,
)
def create_loan(
    employee_id: str, body: LoanCreate, db: Session = Depends(get_db)
):
    get_or_404(db, Employee, employee_id, "Employee")
    loan = Loan(
        employee_id=employee_id,
        loan_date=body.loan_date,
        total_amount=body.total_amount,
        monthly_deduction=body.monthly_deduction,
        description=body.description,
        remaining_balance=body.total_amount,
        status="active",
    )
    db.add(loan)
    db.flush()

    # Initial disbursement transaction
    initial_tx = LoanTransaction(
        loan_id=loan.id,
        employee_id=employee_id,
        transaction_date=body.loan_date,
        description=f"Loan disbursement: {body.description or 'New loan'}",
        debit=body.total_amount,
        credit=0,
        balance=body.total_amount,
    )
    db.add(initial_tx)
    db.commit()
    db.refresh(loan)
    return loan


# ── Combined ledger ────────────────────────────────────────────────────────────

@router.get(
    "/employees/{employee_id}/loan-ledger",
    response_model=List[CombinedLedgerRow],
)
def get_combined_loan_ledger(employee_id: str, db: Session = Depends(get_db)):
    """
    Returns all loan transactions for an employee across all loans,
    sorted by transaction_date, with a running combined balance.
    """
    get_or_404(db, Employee, employee_id, "Employee")

    transactions = (
        db.query(LoanTransaction)
        .join(Loan, LoanTransaction.loan_id == Loan.id)
        .filter(LoanTransaction.employee_id == employee_id)
        .order_by(
            LoanTransaction.transaction_date,
            LoanTransaction.created_at,
        )
        .all()
    )

    # Build combined running balance
    combined_balance = 0
    rows = []
    for tx in transactions:
        combined_balance = combined_balance + tx.debit - tx.credit
        rows.append(
            CombinedLedgerRow(
                id=tx.id,
                loan_id=tx.loan_id,
                loan_description=tx.loan.description if tx.loan else None,
                transaction_date=tx.transaction_date,
                description=tx.description,
                debit=tx.debit,
                credit=tx.credit,
                combined_balance=max(0, combined_balance),
                created_at=tx.created_at,
            )
        )
    return rows


# ── Individual loan CRUD ───────────────────────────────────────────────────────

@router.get("/loans/{loan_id}", response_model=LoanOut)
def get_loan(loan_id: str, db: Session = Depends(get_db)):
    return get_or_404(db, Loan, loan_id, "Loan")


@router.put("/loans/{loan_id}", response_model=LoanOut)
def update_loan(loan_id: str, body: LoanUpdate, db: Session = Depends(get_db)):
    loan = get_or_404(db, Loan, loan_id, "Loan")
    for field, value in body.model_dump(exclude_none=True).items():
        setattr(loan, field, value)
    db.commit()
    db.refresh(loan)
    return loan


@router.delete("/loans/{loan_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_loan(loan_id: str, db: Session = Depends(get_db)):
    loan = get_or_404(db, Loan, loan_id, "Loan")
    db.delete(loan)
    db.commit()


# ── Loan transactions ──────────────────────────────────────────────────────────

@router.get(
    "/loans/{loan_id}/transactions",
    response_model=List[LoanTransactionOut],
)
def get_loan_transactions(loan_id: str, db: Session = Depends(get_db)):
    get_or_404(db, Loan, loan_id, "Loan")
    return (
        db.query(LoanTransaction)
        .filter(LoanTransaction.loan_id == loan_id)
        .order_by(LoanTransaction.transaction_date, LoanTransaction.created_at)
        .all()
    )


@router.post(
    "/loans/{loan_id}/transactions",
    response_model=LoanTransactionOut,
    status_code=status.HTTP_201_CREATED,
)
def add_loan_transaction(
    loan_id: str,
    body: LoanTransactionCreate,
    db: Session = Depends(get_db),
):
    loan = get_or_404(db, Loan, loan_id, "Loan")

    # Get last individual loan balance
    last_tx = (
        db.query(LoanTransaction)
        .filter(LoanTransaction.loan_id == loan_id)
        .order_by(
            LoanTransaction.transaction_date.desc(),
            LoanTransaction.created_at.desc(),
        )
        .first()
    )
    prev_balance = last_tx.balance if last_tx else loan.remaining_balance
    new_balance = max(0, prev_balance + body.debit - body.credit)

    tx = LoanTransaction(
        loan_id=loan_id,
        employee_id=loan.employee_id,
        transaction_date=body.transaction_date,
        description=body.description,
        debit=body.debit,
        credit=body.credit,
        balance=new_balance,
    )
    db.add(tx)

    loan.remaining_balance = new_balance
    if loan.remaining_balance <= 0:
        loan.status = "paid"

    db.commit()
    db.refresh(tx)
    return tx
