from sqlalchemy.orm import Session, joinedload
from typing import Optional, List
from .models import Loancalculation, Amortizationscheduleentry


def get_by_id(db: Session, entity_id: str) -> Optional[Loancalculation]:
    return db.query(Loancalculation).filter(Loancalculation.id == entity_id).first()


def list_all(db: Session, limit: int = 20, offset: int = 0, **filters) -> List[Loancalculation]:
    query = db.query(Loancalculation)
    if filters.get("session_id"):
        query = query.filter(Loancalculation.session_id == filters["session_id"])
    return query.order_by(Loancalculation.created_at.desc()).limit(limit).offset(offset).all()


def create(db: Session, data: dict) -> Loancalculation:
    obj = Loancalculation(**data)
    db.add(obj)
    db.flush()
    return obj


def update(db: Session, entity_id: str, data: dict) -> Optional[Loancalculation]:
    obj = db.query(Loancalculation).filter(Loancalculation.id == entity_id).first()
    if not obj:
        return None
    for key, value in data.items():
        setattr(obj, key, value)
    db.flush()
    return obj


def delete(db: Session, entity_id: str) -> bool:
    obj = db.query(Loancalculation).filter(Loancalculation.id == entity_id).first()
    if not obj:
        return False
    db.delete(obj)
    db.flush()
    return True


def get_with_details(db: Session, entity_id: str) -> Optional[Loancalculation]:
    return (
        db.query(Loancalculation)
        .options(
            joinedload(Loancalculation.amortization_schedule_entries)
        )
        .filter(Loancalculation.id == entity_id)
        .first()
    )


def get_schedule_entry_by_id(db: Session, entry_id: str) -> Optional[Amortizationscheduleentry]:
    return db.query(Amortizationscheduleentry).filter(Amortizationscheduleentry.id == entry_id).first()


def list_schedule_entries(db: Session, loan_calculation_id: str, limit: int = 600, offset: int = 0) -> List[Amortizationscheduleentry]:
    return (
        db.query(Amortizationscheduleentry)
        .filter(Amortizationscheduleentry.loan_calculation_id == loan_calculation_id)
        .order_by(Amortizationscheduleentry.payment_number)
        .limit(limit)
        .offset(offset)
        .all()
    )


def create_schedule_entry(db: Session, data: dict) -> Amortizationscheduleentry:
    obj = Amortizationscheduleentry(**data)
    db.add(obj)
    db.flush()
    return obj


def update_schedule_entry(db: Session, entry_id: str, data: dict) -> Optional[Amortizationscheduleentry]:
    obj = db.query(Amortizationscheduleentry).filter(Amortizationscheduleentry.id == entry_id).first()
    if not obj:
        return None
    for key, value in data.items():
        setattr(obj, key, value)
    db.flush()
    return obj


def delete_schedule_entry(db: Session, entry_id: str) -> bool:
    obj = db.query(Amortizationscheduleentry).filter(Amortizationscheduleentry.id == entry_id).first()
    if not obj:
        return False
    db.delete(obj)
    db.flush()
    return True


def create_bulk_schedule_entries(db: Session, entries_data: List[dict]) -> List[Amortizationscheduleentry]:
    entries = [Amortizationscheduleentry(**data) for data in entries_data]
    db.add_all(entries)
    db.flush()
    return entries