import uuid
from sqlalchemy import Column, String, Integer, Date, ForeignKey, CheckConstraint, DateTime, Index, Numeric
from sqlalchemy.orm import relationship
from utils.utils import Base, utc_now


class Calculation(Base):
    __tablename__ = "calculations"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    principal = Column(Numeric(15, 2), nullable=False)
    annual_interest_rate = Column(Numeric(5, 3), nullable=False)
    loan_term_months = Column(Integer, nullable=False)
    monthly_payment = Column(Numeric(15, 2), nullable=False)
    total_interest = Column(Numeric(15, 2), nullable=False)
    total_amount_paid = Column(Numeric(15, 2), nullable=False)
    calculation_method = Column(String(100), nullable=False)
    start_date = Column(Date, nullable=True)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)

    amortization_schedule_entries = relationship(
        "Amortizationscheduleentry",
        back_populates="calculation",
        cascade="all, delete-orphan",
        passive_deletes=True,
    )

    __table_args__ = (
        CheckConstraint("principal > 0", name="ck_calculations_principal_pos"),
        CheckConstraint("annual_interest_rate >= 0 AND annual_interest_rate <= 100", name="ck_calculations_rate_range"),
        CheckConstraint("loan_term_months > 0 AND loan_term_months <= 360", name="ck_calculations_term_range"),
    )


class Amortizationscheduleentry(Base):
    __tablename__ = "amortization_schedule_entries"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    calculation_id = Column(String(36), ForeignKey("calculations.id", ondelete="CASCADE"), nullable=False, index=True)
    payment_number = Column(Integer, nullable=False)
    payment_date = Column(Date, nullable=False)
    beginning_balance = Column(Numeric(15, 2), nullable=False)
    payment_amount = Column(Numeric(15, 2), nullable=False)
    principal_payment = Column(Numeric(15, 2), nullable=False)
    interest_payment = Column(Numeric(15, 2), nullable=False)
    ending_balance = Column(Numeric(15, 2), nullable=False)
    cumulative_interest = Column(Numeric(15, 2), nullable=False)
    created_at = Column(DateTime(timezone=True), default=utc_now, nullable=False)
    updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False)

    calculation = relationship("Calculation", back_populates="amortization_schedule_entries")

    __table_args__ = (
        CheckConstraint("payment_number > 0", name="ck_schedule_payment_number_pos"),
        CheckConstraint("beginning_balance >= 0", name="ck_schedule_beginning_balance_nonneg"),
        CheckConstraint("payment_amount >= 0", name="ck_schedule_payment_amount_nonneg"),
        CheckConstraint("principal_payment >= 0", name="ck_schedule_principal_payment_nonneg"),
        CheckConstraint("interest_payment >= 0", name="ck_schedule_interest_payment_nonneg"),
        CheckConstraint("ending_balance >= 0", name="ck_schedule_ending_balance_nonneg"),
        CheckConstraint("cumulative_interest >= 0", name="ck_schedule_cumulative_interest_nonneg"),
        Index("ix_schedule_calculation_payment", "calculation_id", "payment_number"),
    )