"""Vendor Product model with override pattern.

This model represents a vendor's copy of a marketplace product with the ability
to override any field. The override pattern works as follows:
- NULL value = inherit from marketplace_product
- Non-NULL value = vendor-specific override

This allows vendors to customize pricing, images, descriptions etc. while
still being able to "reset to source" by setting values back to NULL.

Money values are stored as integer cents (e.g., €105.91 = 10591).
See docs/architecture/money-handling.md for details.
"""

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

from app.core.database import Base
from app.utils.money import cents_to_euros, euros_to_cents
from models.database.base import TimestampMixin


class Product(Base, TimestampMixin):
    """Vendor-specific product with override capability.

    Each vendor can have their own version of a marketplace product with
    custom pricing, images, and other overrides. Fields set to NULL
    inherit their value from the linked marketplace_product.

    Price fields use integer cents for precision (€19.99 = 1999 cents).
    """

    __tablename__ = "products"

    id = Column(Integer, primary_key=True, index=True)
    vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False)
    marketplace_product_id = Column(
        Integer, ForeignKey("marketplace_products.id"), nullable=False
    )

    # === VENDOR REFERENCE ===
    vendor_sku = Column(String, index=True)  # Vendor's internal SKU

    # === PRODUCT IDENTIFIERS ===
    # GTIN (Global Trade Item Number) - barcode for EAN matching with orders
    # Populated from MarketplaceProduct.gtin during product import
    gtin = Column(String(50), index=True)  # EAN/UPC barcode number
    gtin_type = Column(String(20))  # Format: gtin13, gtin14, gtin12, gtin8, isbn13, isbn10

    # === OVERRIDABLE FIELDS (NULL = inherit from marketplace_product) ===
    # Pricing - stored as integer cents (€19.99 = 1999)
    price_cents = Column(Integer)  # Price in cents
    sale_price_cents = Column(Integer)  # Sale price in cents
    currency = Column(String(3))

    # Product Info
    brand = Column(String)
    condition = Column(String)
    availability = Column(String)

    # Media
    primary_image_url = Column(String)
    additional_images = Column(JSON)

    # Digital Product Overrides
    download_url = Column(String)
    license_type = Column(String(50))

    # === TAX / VAT ===
    # Luxembourg VAT rates: 0 (exempt), 3 (super-reduced), 8 (reduced), 14 (intermediate), 17 (standard)
    # Prices are stored as gross (VAT-inclusive). Tax rate is used for profit calculation.
    tax_rate_percent = Column(Integer, default=17, nullable=False)

    # === SUPPLIER TRACKING & COST ===
    supplier = Column(String(50))  # 'codeswholesale', 'internal', etc.
    supplier_product_id = Column(String)  # Supplier's product reference
    cost_cents = Column(Integer)  # What vendor pays to acquire (in cents) - for profit calculation
    margin_percent_x100 = Column(Integer)  # Markup percentage * 100 (e.g., 25.5% = 2550)

    # === VENDOR-SPECIFIC (No inheritance) ===
    is_featured = Column(Boolean, default=False)
    is_active = Column(Boolean, default=True)
    display_order = Column(Integer, default=0)

    # Inventory Settings
    min_quantity = Column(Integer, default=1)
    max_quantity = Column(Integer)

    # Digital Fulfillment
    fulfillment_email_template = Column(String)  # Template name for digital delivery

    # === RELATIONSHIPS ===
    vendor = relationship("Vendor", back_populates="products")
    marketplace_product = relationship(
        "MarketplaceProduct", back_populates="vendor_products"
    )
    translations = relationship(
        "ProductTranslation",
        back_populates="product",
        cascade="all, delete-orphan",
    )
    inventory_entries = relationship(
        "Inventory", back_populates="product", cascade="all, delete-orphan"
    )

    # === CONSTRAINTS & INDEXES ===
    __table_args__ = (
        UniqueConstraint(
            "vendor_id", "marketplace_product_id", name="uq_vendor_marketplace_product"
        ),
        Index("idx_product_vendor_active", "vendor_id", "is_active"),
        Index("idx_product_vendor_featured", "vendor_id", "is_featured"),
        Index("idx_product_vendor_sku", "vendor_id", "vendor_sku"),
        Index("idx_product_supplier", "supplier", "supplier_product_id"),
    )

    # === OVERRIDABLE FIELDS LIST ===
    OVERRIDABLE_FIELDS = [
        "price_cents",
        "sale_price_cents",
        "currency",
        "brand",
        "condition",
        "availability",
        "primary_image_url",
        "additional_images",
        "download_url",
        "license_type",
    ]

    def __repr__(self):
        return (
            f"<Product(id={self.id}, vendor_id={self.vendor_id}, "
            f"vendor_sku='{self.vendor_sku}')>"
        )

    # === PRICE PROPERTIES (Euro convenience accessors) ===

    @property
    def price(self) -> float | None:
        """Get price in euros (for API/display)."""
        if self.price_cents is not None:
            return cents_to_euros(self.price_cents)
        return None

    @price.setter
    def price(self, value: float | None):
        """Set price from euros."""
        self.price_cents = euros_to_cents(value) if value is not None else None

    @property
    def sale_price(self) -> float | None:
        """Get sale price in euros (for API/display)."""
        if self.sale_price_cents is not None:
            return cents_to_euros(self.sale_price_cents)
        return None

    @sale_price.setter
    def sale_price(self, value: float | None):
        """Set sale price from euros."""
        self.sale_price_cents = euros_to_cents(value) if value is not None else None

    @property
    def cost(self) -> float | None:
        """Get cost in euros (what vendor pays to acquire)."""
        if self.cost_cents is not None:
            return cents_to_euros(self.cost_cents)
        return None

    @cost.setter
    def cost(self, value: float | None):
        """Set cost from euros."""
        self.cost_cents = euros_to_cents(value) if value is not None else None

    @property
    def margin_percent(self) -> float | None:
        """Get margin percent (e.g., 25.5)."""
        if self.margin_percent_x100 is not None:
            return self.margin_percent_x100 / 100.0
        return None

    @margin_percent.setter
    def margin_percent(self, value: float | None):
        """Set margin percent."""
        self.margin_percent_x100 = int(value * 100) if value is not None else None

    # === TAX / PROFIT CALCULATION PROPERTIES ===

    @property
    def net_price_cents(self) -> int | None:
        """Calculate net price (excluding VAT) from gross price.

        Formula: Net = Gross / (1 + rate/100)
        Example: €119 gross at 17% VAT = €119 / 1.17 = €101.71 net
        """
        gross = self.effective_price_cents
        if gross is None:
            return None
        # Use integer math to avoid floating point issues
        # Net = Gross * 100 / (100 + rate)
        return int(gross * 100 / (100 + self.tax_rate_percent))

    @property
    def net_price(self) -> float | None:
        """Get net price in euros."""
        cents = self.net_price_cents
        return cents_to_euros(cents) if cents is not None else None

    @property
    def vat_amount_cents(self) -> int | None:
        """Calculate VAT amount in cents.

        Formula: VAT = Gross - Net
        """
        gross = self.effective_price_cents
        net = self.net_price_cents
        if gross is None or net is None:
            return None
        return gross - net

    @property
    def vat_amount(self) -> float | None:
        """Get VAT amount in euros."""
        cents = self.vat_amount_cents
        return cents_to_euros(cents) if cents is not None else None

    @property
    def profit_cents(self) -> int | None:
        """Calculate profit in cents.

        Formula: Profit = Net Revenue - Cost
        Returns None if cost is not set.
        """
        net = self.net_price_cents
        if net is None or self.cost_cents is None:
            return None
        return net - self.cost_cents

    @property
    def profit(self) -> float | None:
        """Get profit in euros."""
        cents = self.profit_cents
        return cents_to_euros(cents) if cents is not None else None

    @property
    def profit_margin_percent(self) -> float | None:
        """Calculate profit margin as percentage of net revenue.

        Formula: Margin% = (Profit / Net) * 100
        Example: €41.71 profit on €101.71 net = 41.0% margin
        """
        net = self.net_price_cents
        profit = self.profit_cents
        if net is None or profit is None or net == 0:
            return None
        return round((profit / net) * 100, 2)

    # === EFFECTIVE PROPERTIES (Override Pattern) ===

    @property
    def effective_price_cents(self) -> int | None:
        """Get price in cents (vendor override or marketplace fallback)."""
        if self.price_cents is not None:
            return self.price_cents
        mp = self.marketplace_product
        return mp.price_cents if mp else None

    @property
    def effective_price(self) -> float | None:
        """Get price in euros (vendor override or marketplace fallback)."""
        cents = self.effective_price_cents
        return cents_to_euros(cents) if cents is not None else None

    @property
    def effective_sale_price_cents(self) -> int | None:
        """Get sale price in cents (vendor override or marketplace fallback)."""
        if self.sale_price_cents is not None:
            return self.sale_price_cents
        mp = self.marketplace_product
        return mp.sale_price_cents if mp else None

    @property
    def effective_sale_price(self) -> float | None:
        """Get sale price in euros (vendor override or marketplace fallback)."""
        cents = self.effective_sale_price_cents
        return cents_to_euros(cents) if cents is not None else None

    @property
    def effective_currency(self) -> str:
        """Get currency (vendor override or marketplace fallback)."""
        if self.currency is not None:
            return self.currency
        mp = self.marketplace_product
        return mp.currency if mp else "EUR"

    @property
    def effective_brand(self) -> str | None:
        """Get brand (vendor override or marketplace fallback)."""
        if self.brand is not None:
            return self.brand
        mp = self.marketplace_product
        return mp.brand if mp else None

    @property
    def effective_condition(self) -> str | None:
        """Get condition (vendor override or marketplace fallback)."""
        if self.condition is not None:
            return self.condition
        mp = self.marketplace_product
        return mp.condition if mp else None

    @property
    def effective_availability(self) -> str | None:
        """Get availability (vendor override or marketplace fallback)."""
        if self.availability is not None:
            return self.availability
        mp = self.marketplace_product
        return mp.availability if mp else None

    @property
    def effective_primary_image_url(self) -> str | None:
        """Get primary image (vendor override or marketplace fallback)."""
        if self.primary_image_url is not None:
            return self.primary_image_url
        mp = self.marketplace_product
        return mp.image_link if mp else None

    @property
    def effective_additional_images(self) -> list | None:
        """Get additional images (vendor override or marketplace fallback)."""
        if self.additional_images is not None:
            return self.additional_images
        mp = self.marketplace_product
        if mp and mp.additional_images:
            return mp.additional_images
        return None

    @property
    def is_digital(self) -> bool:
        """Check if this is a digital product."""
        mp = self.marketplace_product
        return mp.is_digital if mp else False

    @property
    def product_type(self) -> str:
        """Get product type from marketplace product."""
        mp = self.marketplace_product
        return mp.product_type_enum if mp else "physical"

    # === INVENTORY PROPERTIES ===

    # Constant for unlimited inventory (digital products)
    UNLIMITED_INVENTORY = 999999

    @property
    def has_unlimited_inventory(self) -> bool:
        """Check if product has unlimited inventory.

        Digital products have unlimited inventory by default.
        They don't require physical stock tracking.
        """
        return self.is_digital

    @property
    def total_inventory(self) -> int:
        """Calculate total inventory across all locations.

        Digital products return unlimited inventory.
        """
        if self.has_unlimited_inventory:
            return self.UNLIMITED_INVENTORY
        return sum(inv.quantity for inv in self.inventory_entries)

    @property
    def available_inventory(self) -> int:
        """Calculate available inventory (total - reserved).

        Digital products return unlimited inventory since they
        don't have physical stock constraints.
        """
        if self.has_unlimited_inventory:
            return self.UNLIMITED_INVENTORY
        return sum(inv.available_quantity for inv in self.inventory_entries)

    # === OVERRIDE INFO METHOD ===

    def get_override_info(self) -> dict:
        """Get all fields with inheritance flags.

        Returns a dict with effective values, override flags, and source values.
        Similar to Vendor.get_contact_info_with_inheritance().
        """
        mp = self.marketplace_product
        return {
            # Price
            "price": self.effective_price,
            "price_cents": self.effective_price_cents,
            "price_overridden": self.price_cents is not None,
            "price_source": cents_to_euros(mp.price_cents) if mp and mp.price_cents else None,
            # Sale Price
            "sale_price": self.effective_sale_price,
            "sale_price_cents": self.effective_sale_price_cents,
            "sale_price_overridden": self.sale_price_cents is not None,
            "sale_price_source": cents_to_euros(mp.sale_price_cents) if mp and mp.sale_price_cents else None,
            # Currency
            "currency": self.effective_currency,
            "currency_overridden": self.currency is not None,
            "currency_source": mp.currency if mp else None,
            # Brand
            "brand": self.effective_brand,
            "brand_overridden": self.brand is not None,
            "brand_source": mp.brand if mp else None,
            # Condition
            "condition": self.effective_condition,
            "condition_overridden": self.condition is not None,
            "condition_source": mp.condition if mp else None,
            # Availability
            "availability": self.effective_availability,
            "availability_overridden": self.availability is not None,
            "availability_source": mp.availability if mp else None,
            # Images
            "primary_image_url": self.effective_primary_image_url,
            "primary_image_url_overridden": self.primary_image_url is not None,
            "primary_image_url_source": mp.image_link if mp else None,
            # Product type info
            "is_digital": self.is_digital,
            "product_type": self.product_type,
        }

    # === RESET METHODS ===

    def reset_field_to_source(self, field_name: str) -> bool:
        """Reset a single field to inherit from marketplace product.

        Args:
            field_name: Name of the field to reset

        Returns:
            True if field was reset, False if field is not overridable
        """
        if field_name in self.OVERRIDABLE_FIELDS:
            setattr(self, field_name, None)
            return True
        return False

    def reset_all_to_source(self) -> None:
        """Reset all overridable fields to inherit from marketplace product."""
        for field in self.OVERRIDABLE_FIELDS:
            setattr(self, field, None)

    def reset_fields_to_source(self, field_names: list[str]) -> list[str]:
        """Reset multiple fields to inherit from marketplace product.

        Args:
            field_names: List of field names to reset

        Returns:
            List of fields that were successfully reset
        """
        reset_fields = []
        for field in field_names:
            if self.reset_field_to_source(field):
                reset_fields.append(field)
        return reset_fields

    # === TRANSLATION HELPERS ===

    def get_translation(self, language: str) -> "ProductTranslation | None":
        """Get vendor translation for a specific language."""
        for t in self.translations:
            if t.language == language:
                return t
        return None

    def get_effective_title(self, language: str = "en") -> str | None:
        """Get title with vendor override or marketplace fallback."""
        # Check vendor translation first
        translation = self.get_translation(language)
        if translation and translation.title:
            return translation.title

        # Fall back to marketplace translation
        mp = self.marketplace_product
        if mp:
            return mp.get_title(language)

        return None

    def get_effective_description(self, language: str = "en") -> str | None:
        """Get description with vendor override or marketplace fallback."""
        # Check vendor translation first
        translation = self.get_translation(language)
        if translation and translation.description:
            return translation.description

        # Fall back to marketplace translation
        mp = self.marketplace_product
        if mp:
            return mp.get_description(language)

        return None
