# app/modules/orders/models/invoice.py
"""
Invoice database models for the OMS.

Provides models for:
- StoreInvoiceSettings: Per-store invoice configuration (merchant details, VAT, numbering)
- Invoice: Invoice records with snapshots of seller/buyer details
"""

import enum

from sqlalchemy import (
    Boolean,
    Column,
    DateTime,
    ForeignKey,
    Index,
    Integer,
    Numeric,
    String,
    Text,
)
from sqlalchemy.dialects.sqlite import JSON
from sqlalchemy.orm import relationship

from app.core.database import Base
from models.database.base import TimestampMixin


class StoreInvoiceSettings(Base, TimestampMixin):
    """
    Per-store invoice configuration.

    Stores merchant details, VAT number, invoice numbering preferences,
    and payment information for invoice generation.

    One-to-one relationship with Store.
    """

    __tablename__ = "store_invoice_settings"

    id = Column(Integer, primary_key=True, index=True)
    store_id = Column(
        Integer, ForeignKey("stores.id"), unique=True, nullable=False, index=True
    )

    # Legal merchant details for invoice header
    merchant_name = Column(String(255), nullable=False)  # Legal name for invoices
    merchant_address = Column(String(255), nullable=True)  # Street address
    merchant_city = Column(String(100), nullable=True)
    merchant_postal_code = Column(String(20), nullable=True)
    merchant_country = Column(String(2), nullable=False, default="LU")  # ISO country code

    # VAT information
    vat_number = Column(String(50), nullable=True)  # e.g., "LU12345678"
    is_vat_registered = Column(Boolean, default=True, nullable=False)

    # OSS (One-Stop-Shop) for EU VAT
    is_oss_registered = Column(Boolean, default=False, nullable=False)
    oss_registration_country = Column(String(2), nullable=True)  # ISO country code

    # Invoice numbering
    invoice_prefix = Column(String(20), default="INV", nullable=False)
    invoice_next_number = Column(Integer, default=1, nullable=False)
    invoice_number_padding = Column(Integer, default=5, nullable=False)  # e.g., INV00001

    # Payment information
    payment_terms = Column(Text, nullable=True)  # e.g., "Payment due within 30 days"
    bank_name = Column(String(255), nullable=True)
    bank_iban = Column(String(50), nullable=True)
    bank_bic = Column(String(20), nullable=True)

    # Invoice footer
    footer_text = Column(Text, nullable=True)  # Custom footer text

    # Default VAT rate for Luxembourg invoices (17% standard)
    default_vat_rate = Column(Numeric(5, 2), default=17.00, nullable=False)

    # Relationships
    store = relationship("Store", back_populates="invoice_settings")

    def __repr__(self):
        return f"<StoreInvoiceSettings(store_id={self.store_id}, merchant='{self.merchant_name}')>"

    def get_next_invoice_number(self) -> str:
        """Generate the next invoice number and increment counter."""
        number = str(self.invoice_next_number).zfill(self.invoice_number_padding)
        return f"{self.invoice_prefix}{number}"


class InvoiceStatus(str, enum.Enum):
    """Invoice status enumeration."""

    DRAFT = "draft"
    ISSUED = "issued"
    PAID = "paid"
    CANCELLED = "cancelled"


class VATRegime(str, enum.Enum):
    """VAT regime for invoice calculation."""

    DOMESTIC = "domestic"  # Same country as seller
    OSS = "oss"  # EU cross-border with OSS registration
    REVERSE_CHARGE = "reverse_charge"  # B2B with valid VAT number
    ORIGIN = "origin"  # Cross-border without OSS (use origin VAT)
    EXEMPT = "exempt"  # VAT exempt


class Invoice(Base, TimestampMixin):
    """
    Invoice record with snapshots of seller/buyer details.

    Stores complete invoice data including snapshots of seller and buyer
    details at time of creation for audit purposes.
    """

    __tablename__ = "invoices"

    id = Column(Integer, primary_key=True, index=True)
    store_id = Column(Integer, ForeignKey("stores.id"), nullable=False, index=True)
    order_id = Column(Integer, ForeignKey("orders.id"), nullable=True, index=True)

    # Invoice identification
    invoice_number = Column(String(50), nullable=False)
    invoice_date = Column(DateTime(timezone=True), nullable=False)

    # Status
    status = Column(String(20), default=InvoiceStatus.DRAFT.value, nullable=False)

    # Seller details snapshot (captured at invoice creation)
    seller_details = Column(JSON, nullable=False)
    # Structure: {
    #   "merchant_name": str,
    #   "address": str,
    #   "city": str,
    #   "postal_code": str,
    #   "country": str,
    #   "vat_number": str | None
    # }

    # Buyer details snapshot (captured at invoice creation)
    buyer_details = Column(JSON, nullable=False)
    # Structure: {
    #   "name": str,
    #   "email": str,
    #   "address": str,
    #   "city": str,
    #   "postal_code": str,
    #   "country": str,
    #   "vat_number": str | None (for B2B)
    # }

    # Line items snapshot
    line_items = Column(JSON, nullable=False)
    # Structure: [{
    #   "description": str,
    #   "quantity": int,
    #   "unit_price_cents": int,
    #   "total_cents": int,
    #   "sku": str | None,
    #   "ean": str | None
    # }]

    # VAT information
    vat_regime = Column(String(20), default=VATRegime.DOMESTIC.value, nullable=False)
    destination_country = Column(String(2), nullable=True)  # For OSS invoices
    vat_rate = Column(Numeric(5, 2), nullable=False)  # e.g., 17.00 for 17%
    vat_rate_label = Column(String(50), nullable=True)  # e.g., "Luxembourg Standard VAT"

    # Amounts (stored in cents for precision)
    currency = Column(String(3), default="EUR", nullable=False)
    subtotal_cents = Column(Integer, nullable=False)  # Before VAT
    vat_amount_cents = Column(Integer, nullable=False)  # VAT amount
    total_cents = Column(Integer, nullable=False)  # After VAT

    # Payment information
    payment_terms = Column(Text, nullable=True)
    bank_details = Column(JSON, nullable=True)  # IBAN, BIC snapshot
    footer_text = Column(Text, nullable=True)

    # PDF storage
    pdf_generated_at = Column(DateTime(timezone=True), nullable=True)
    pdf_path = Column(String(500), nullable=True)  # Path to stored PDF

    # Notes
    notes = Column(Text, nullable=True)  # Internal notes

    # Relationships
    store = relationship("Store", back_populates="invoices")
    order = relationship("Order", back_populates="invoices")

    __table_args__ = (
        Index("idx_invoice_store_number", "store_id", "invoice_number", unique=True),
        Index("idx_invoice_store_date", "store_id", "invoice_date"),
        Index("idx_invoice_status", "store_id", "status"),
    )

    def __repr__(self):
        return f"<Invoice(id={self.id}, number='{self.invoice_number}', status='{self.status}')>"

    @property
    def subtotal(self) -> float:
        """Get subtotal in EUR."""
        return self.subtotal_cents / 100

    @property
    def vat_amount(self) -> float:
        """Get VAT amount in EUR."""
        return self.vat_amount_cents / 100

    @property
    def total(self) -> float:
        """Get total in EUR."""
        return self.total_cents / 100
