import enum
from datetime import datetime
from typing import Optional, TYPE_CHECKING
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func
from src.apps.base.models.base import Base

if TYPE_CHECKING:
    from src.apps.merchants.models.merchant import Merchant


class BillingStatus(str, enum.Enum):
    PENDING = "pending"
    PROCESSING = "processing"
    PAID = "paid"
    FAILED = "failed"
    RETRYING = "retrying"
    SKIPPED = "skipped"


class BillingRecord(Base):
    __tablename__ = "billing_records"
    __table_args__ = (
        UniqueConstraint("merchant_id", "period_start", name="uq_billing_record_merchant_period"),
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    merchant_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("merchants.id"), nullable=False, index=True
    )
    template_id: Mapped[Optional[int]] = mapped_column(
        Integer, ForeignKey("pricing_templates.id"), nullable=True
    )
    period_start: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
    period_end: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
    total_volume_cents: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    total_platform_fee_cents: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    monthly_fee_cents: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    total_due_cents: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default=BillingStatus.PENDING)
    charge_txn_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    retry_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    last_error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    updated_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True, onupdate=func.now()
    )

    merchant: Mapped["Merchant"] = relationship("Merchant")
