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


class CalculationInput(Base):
    __tablename__ = "calculation_inputs"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    monthly_investment = Column(Numeric(12, 2), nullable=False)
    expected_return_rate = Column(Numeric(5, 2), nullable=False)
    time_period = Column(Integer, nullable=False)
    timestamp = Column(DateTime(timezone=True), nullable=False, default=utc_now)
    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_result = relationship("CalculationResult", back_populates="calculation_input", uselist=False, cascade="all, delete-orphan", passive_deletes=True)
    chart_data_points = relationship("ChartDataPoint", back_populates="calculation_input", cascade="all, delete-orphan", passive_deletes=True)

    __table_args__ = (
        CheckConstraint("monthly_investment >= 0", name="ck_calculation_inputs_monthly_investment_nonneg"),
        CheckConstraint("expected_return_rate >= 0 AND expected_return_rate <= 100", name="ck_calculation_inputs_expected_return_rate_range"),
        CheckConstraint("time_period > 0", name="ck_calculation_inputs_time_period_pos"),
    )


class CalculationResult(Base):
    __tablename__ = "calculation_results"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    calculation_input_id = Column(String(36), ForeignKey("calculation_inputs.id", ondelete="CASCADE"), nullable=False, index=True, unique=True)
    total_investment = Column(Numeric(15, 2), nullable=False)
    estimated_returns = Column(Numeric(15, 2), nullable=False)
    maturity_value = 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_input = relationship("CalculationInput", back_populates="calculation_result")

    __table_args__ = (
        CheckConstraint("total_investment >= 0", name="ck_calculation_results_total_investment_nonneg"),
        CheckConstraint("maturity_value >= 0", name="ck_calculation_results_maturity_value_nonneg"),
    )


class ChartDataPoint(Base):
    __tablename__ = "chart_data_points"

    id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
    calculation_input_id = Column(String(36), ForeignKey("calculation_inputs.id", ondelete="CASCADE"), nullable=False, index=True)
    year = Column(Integer, nullable=False)
    invested_amount = Column(Numeric(15, 2), nullable=False)
    projected_value = 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_input = relationship("CalculationInput", back_populates="chart_data_points")

    __table_args__ = (
        CheckConstraint("year > 0", name="ck_chart_data_points_year_pos"),
        CheckConstraint("invested_amount >= 0", name="ck_chart_data_points_invested_amount_nonneg"),
        CheckConstraint("projected_value >= 0", name="ck_chart_data_points_projected_value_nonneg"),
        Index("ix_chart_data_points_calculation_input_year", "calculation_input_id", "year"),
    )