from sqlalchemy import Integer, String, Boolean, ForeignKey, Numeric, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
from app.models.base import TemporalConfigMixin
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from app.models.lender import Product

class ProductConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "product_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    # Relationship back to product
    product: Mapped["Product"] = relationship(back_populates="configurations")

class ChargeMaster(Base):
    __tablename__ = "charge_master"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    code: Mapped[str] = mapped_column(String(100), unique=True, index=True, nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(String(500), nullable=True)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

class ChargeConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "charge_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    charge_master_id: Mapped[int] = mapped_column(Integer, ForeignKey("charge_master.id"), nullable=False)
    
    charge_type: Mapped[str] = mapped_column(String(50), nullable=False)  # FIXED, PERCENTAGE
    value: Mapped[float] = mapped_column(Numeric(15, 4), nullable=False)
    is_taxable: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    tax_percentage: Mapped[float] = mapped_column(Numeric(5, 2), default=18.00, nullable=False)
    partner_split: Mapped[dict | None] = mapped_column(JSON, nullable=True)

class AllocationConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "allocation_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    sequence_type: Mapped[str] = mapped_column(String(50), nullable=False)  # REGULAR_EMI, SETTLEMENT, FORECLOSURE, NPA, ADVANCE_COLLECTION
    priority_sequence: Mapped[list[str]] = mapped_column(JSON, nullable=False)  # e.g., ["IPC", "PIC"] -> stored as raw sequence list e.g., ["interest", "principal", "charges"]

class CollectionConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "collection_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    allocation_strategy: Mapped[str] = mapped_column(String(100), nullable=False)  # OLDEST_DUE_FIRST, DUE_DATE_BASED, FUTURE_ALLOCATION
    advance_collection_strategy: Mapped[str] = mapped_column(String(100), nullable=False)  # NO_INTEREST_BENEFIT, INTEREST_BENEFIT
    excess_refund_required: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)

class SpecificCollectionConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "specific_collection_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    collection_type: Mapped[str] = mapped_column(String(100), nullable=False)  # ADVANCE_COLLECTION, etc.
    park_collection: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    metadata_config: Mapped[dict | None] = mapped_column(JSON, nullable=True)

class SettlementConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "settlement_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    max_waiver_percentage: Mapped[float] = mapped_column(Numeric(5, 2), nullable=False)
    maker_checker_required: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    allowed_write_off_limit: Mapped[float] = mapped_column(Numeric(15, 4), nullable=False)

class ForeclosureConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "foreclosure_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    charge_type: Mapped[str] = mapped_column(String(50), nullable=False)  # FIXED, PERCENTAGE, NONE
    charge_value: Mapped[float] = mapped_column(Numeric(15, 4), nullable=False)
    lock_in_period_months: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    rebate_percentage: Mapped[float] = mapped_column(Numeric(5, 2), default=0.00, nullable=False)

class NpaConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "npa_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    dpd_threshold: Mapped[int] = mapped_column(Integer, default=90, nullable=False)
    bucket_classification_rules: Mapped[dict] = mapped_column(JSON, nullable=False)  # e.g., {"0-30": "Standard", "31-60": "SMA-1", "61-90": "SMA-2", "90+": "NPA"}

class WorkflowConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "workflow_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    workflow_type: Mapped[str] = mapped_column(String(100), nullable=False)  # DISBURSEMENT, FORECLOSURE, SETTLEMENT
    approval_levels: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
    role_hierarchy: Mapped[dict] = mapped_column(JSON, nullable=False)  # Role hierarchy JSON metadata

class DisbursementConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "disbursement_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    disbursement_logic: Mapped[str] = mapped_column(String(100), nullable=False)  # ON_OR_BEFORE_DATE, FIXED_DATE
    fixed_day_of_month: Mapped[int | None] = mapped_column(Integer, nullable=True)
    cut_off_hour: Mapped[int] = mapped_column(Integer, default=18, nullable=False)

class EmiConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "emi_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    emi_due_day: Mapped[int] = mapped_column(Integer, default=3, nullable=False)


class InterestConfiguration(Base, TemporalConfigMixin):
    __tablename__ = "interest_configurations"
    
    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)
    
    calculation_basis: Mapped[str] = mapped_column(String(50), nullable=False)  # ACTUAL_365, ACTUAL_360, 30_360, ACTUAL_ACTUAL, DAYS360, IPMT
    emi_type: Mapped[str] = mapped_column(String(50), nullable=False)  # FLAT, REDUCING
    repayment_frequency: Mapped[str] = mapped_column(String(50), default="MONTHLY", nullable=False)
    grace_period_days: Mapped[int] = mapped_column(Integer, default=0, nullable=False)

    # BPI & Rounding Configuration
    bpi_applicable: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)  # Whether BPI is applicable for this product
    bpi_treatment: Mapped[str | None] = mapped_column(String(50), default="ADD_TO_LOAN", nullable=True)  # ADD_TO_LOAN, SEPARATE_BEFORE_EMI, ADD_IN_EMI
    bpi_day_convention: Mapped[str | None] = mapped_column(String(50), default="ACTUAL_365", nullable=True)  # 30_360, ACTUAL_ACTUAL, ACTUAL_365, DAYS360, IPMT
    emi_rounding: Mapped[str | None] = mapped_column(String(20), default="ROUND", nullable=True)  # ROUND_UP, ROUND_DOWN, ROUND
    emi_rounding_digits: Mapped[int | None] = mapped_column(Integer, default=0, nullable=True)  # 0, 1, 2, -1
    interest_rounding: Mapped[str | None] = mapped_column(String(20), default="ROUND", nullable=True)  # ROUND_UP, ROUND_DOWN, ROUND
    interest_rounding_digits: Mapped[int | None] = mapped_column(Integer, default=0, nullable=True)  # 0, 1, 2, -1, -2
    bpi_rounding: Mapped[str | None] = mapped_column(String(20), default="ROUND", nullable=True)  # ROUND_UP, ROUND_DOWN, ROUND
    bpi_rounding_digits: Mapped[int | None] = mapped_column(Integer, default=0, nullable=True)  # 0, 1, 2, -1, -2

class WaiveOffConfiguration(Base, TemporalConfigMixin):
    """
    Defines which charge categories are eligible for waiver on this product,
    and the priority order in which waivers are applied.
    Only BOUNCE and PENAL categories are permitted.
    The ordered list (index 0 = first waived) is stored as JSON.
    Example: ["BOUNCE", "PENAL"] means bounce charges are waived before penal.
    """
    __tablename__ = "waive_off_configurations"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)

    # Ordered list of waiveable charge categories. Allowed values: ["BOUNCE", "PENAL"]
    waiveable_charge_categories: Mapped[list] = mapped_column(JSON, nullable=False)

class RpsConfiguration(Base, TemporalConfigMixin):
    """
    Defines the allowed POS (Principal Outstanding) split options for generating
    Repayment Schedules on this product.
    Each split is a list of integers that must sum to 100.
    Example: [[100], [80, 20], [70, 30]] means three allowed options:
      - Single RPS on full POS
      - Two RPS documents at 80% and 20% of POS
      - Two RPS documents at 70% and 30% of POS
    """
    __tablename__ = "rps_configurations"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    product_id: Mapped[int] = mapped_column(Integer, ForeignKey("products.id"), nullable=False)

    # List of allowed split definitions. Each inner list must sum to 100.
    allowed_splits: Mapped[list] = mapped_column(JSON, nullable=False)
