"""
SQLAlchemy ORM models for Nexus Autoparts.
"""
from sqlalchemy import (
    Column, Integer, String, Float, Boolean, Text, DateTime, ForeignKey,
    UniqueConstraint, Index, func, text
)
from sqlalchemy.dialects.postgresql import JSONB, TSVECTOR
from sqlalchemy.orm import relationship, DeclarativeBase
from datetime import datetime


class Base(DeclarativeBase):
    pass


# ─────────────────────────────────────────────
# Lookup tables
# ─────────────────────────────────────────────

class FuelType(Base):
    __tablename__ = "fuel_type"
    id_fuel = Column(Integer, primary_key=True)
    name_fuel = Column(String(50), nullable=False, unique=True)


class BodyType(Base):
    __tablename__ = "body_type"
    id_body = Column(Integer, primary_key=True)
    name_body = Column(String(50), nullable=False, unique=True)


class Drivetrain(Base):
    __tablename__ = "drivetrain"
    id_drivetrain = Column(Integer, primary_key=True)
    name_drivetrain = Column(String(50), nullable=False, unique=True)


class Transmission(Base):
    __tablename__ = "transmission"
    id_transmission = Column(Integer, primary_key=True)
    name_transmission = Column(String(50), nullable=False, unique=True)


class Material(Base):
    __tablename__ = "materials"
    id_material = Column(Integer, primary_key=True)
    name_material = Column(String(100), nullable=False, unique=True)


class PositionPart(Base):
    __tablename__ = "position_part"
    id_position_part = Column(Integer, primary_key=True)
    name_position_part = Column(String(50), nullable=False, unique=True)


class ManufactureType(Base):
    __tablename__ = "manufacture_type"
    id_type_manu = Column(Integer, primary_key=True)
    name_type_manu = Column(String(50), nullable=False, unique=True)


class QualityTier(Base):
    __tablename__ = "quality_tier"
    id_quality_tier = Column(Integer, primary_key=True)
    name_quality = Column(String(50), nullable=False, unique=True)


class Country(Base):
    __tablename__ = "countries"
    id_country = Column(Integer, primary_key=True)
    name_country = Column(String(100), nullable=False, unique=True)


class ReferenceType(Base):
    __tablename__ = "reference_type"
    id_ref_type = Column(Integer, primary_key=True)
    name_ref_type = Column(String(50), nullable=False, unique=True)


class Shape(Base):
    __tablename__ = "shapes"
    id_shape = Column(Integer, primary_key=True)
    name_shape = Column(String(50), nullable=False, unique=True)


# ─────────────────────────────────────────────
# Core tables
# ─────────────────────────────────────────────

class Brand(Base):
    __tablename__ = "brands"
    id_brand = Column(Integer, primary_key=True)
    name_brand = Column(String(200), nullable=False, unique=True)
    country = Column(String(100))
    founded_year = Column(Integer)
    created_at = Column(DateTime, default=datetime.utcnow)

    models = relationship("Model", back_populates="brand")


class Year(Base):
    __tablename__ = "years"
    id_year = Column(Integer, primary_key=True)
    year_car = Column(Integer, nullable=False, unique=True)
    created_at = Column(DateTime, default=datetime.utcnow)


class Engine(Base):
    __tablename__ = "engines"
    id_engine = Column(Integer, primary_key=True)
    name_engine = Column(String(300), nullable=False)
    displacement_cc = Column(Float)
    cylinders = Column(Integer)
    id_fuel = Column(Integer, ForeignKey("fuel_type.id_fuel"))
    power_hp = Column(Integer)
    torque_nm = Column(Integer)
    engine_code = Column(String(100))
    created_at = Column(DateTime, default=datetime.utcnow)

    fuel_type = relationship("FuelType")


class Model(Base):
    __tablename__ = "models"
    id_model = Column(Integer, primary_key=True)
    brand_id = Column(Integer, ForeignKey("brands.id_brand"), nullable=False)
    name_model = Column(String(300), nullable=False)
    id_body = Column(Integer, ForeignKey("body_type.id_body"))
    generation = Column(String(100))
    production_start_year = Column(Integer)
    production_end_year = Column(Integer)
    created_at = Column(DateTime, default=datetime.utcnow)

    brand = relationship("Brand", back_populates="models")
    body_type = relationship("BodyType")

    __table_args__ = (
        Index("idx_models_brand", "brand_id"),
    )


class ModelYearEngine(Base):
    __tablename__ = "model_year_engine"
    id_mye = Column(Integer, primary_key=True)
    model_id = Column(Integer, ForeignKey("models.id_model"), nullable=False)
    year_id = Column(Integer, ForeignKey("years.id_year"), nullable=False)
    engine_id = Column(Integer, ForeignKey("engines.id_engine"), nullable=False)
    trim_level = Column(String(100))
    id_drivetrain = Column(Integer, ForeignKey("drivetrain.id_drivetrain"))
    id_transmission = Column(Integer, ForeignKey("transmission.id_transmission"))
    created_at = Column(DateTime, default=datetime.utcnow)

    model = relationship("Model")
    year = relationship("Year")
    engine = relationship("Engine")
    drivetrain = relationship("Drivetrain")
    transmission = relationship("Transmission")

    __table_args__ = (
        UniqueConstraint("model_id", "year_id", "engine_id", "trim_level",
                         name="uq_mye_combo"),
        Index("idx_mye_model", "model_id"),
        Index("idx_mye_year", "year_id"),
        Index("idx_mye_engine", "engine_id"),
    )


class PartCategory(Base):
    __tablename__ = "part_categories"
    id_part_category = Column(Integer, primary_key=True)
    name_part_category = Column(String(200), nullable=False)
    name_es = Column(String(200))
    parent_id = Column(Integer, ForeignKey("part_categories.id_part_category"))
    slug = Column(String(200), unique=True)
    icon_name = Column(String(100))
    display_order = Column(Integer, default=0)
    created_at = Column(DateTime, default=datetime.utcnow)

    parent = relationship("PartCategory", remote_side="PartCategory.id_part_category")

    __table_args__ = (
        Index("idx_part_categories_parent", "parent_id"),
        Index("idx_part_categories_slug", "slug"),
    )


class PartGroup(Base):
    __tablename__ = "part_groups"
    id_part_group = Column(Integer, primary_key=True)
    category_id = Column(Integer, ForeignKey("part_categories.id_part_category"), nullable=False)
    name_part_group = Column(String(200), nullable=False)
    name_es = Column(String(200))
    slug = Column(String(200))
    display_order = Column(Integer, default=0)
    created_at = Column(DateTime, default=datetime.utcnow)

    category = relationship("PartCategory")

    __table_args__ = (
        Index("idx_part_groups_category", "category_id"),
    )


class Part(Base):
    __tablename__ = "parts"
    id_part = Column(Integer, primary_key=True)
    oem_part_number = Column(String(100), nullable=False)
    name_part = Column(String(300), nullable=False)
    name_es = Column(String(300))
    group_id = Column(Integer, ForeignKey("part_groups.id_part_group"))
    description = Column(Text)
    description_es = Column(Text)
    weight_kg = Column(Float)
    id_material = Column(Integer, ForeignKey("materials.id_material"))
    created_at = Column(DateTime, default=datetime.utcnow)
    search_vector = Column(TSVECTOR)

    group = relationship("PartGroup")
    material = relationship("Material")

    __table_args__ = (
        Index("idx_parts_oem", "oem_part_number"),
        Index("idx_parts_group", "group_id"),
        Index("idx_parts_search", "search_vector", postgresql_using="gin"),
    )


class VehiclePart(Base):
    __tablename__ = "vehicle_parts"
    id_vehicle_part = Column(Integer, primary_key=True)
    model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye"), nullable=False)
    part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False)
    quantity_required = Column(Integer, default=1)
    id_position_part = Column(Integer, ForeignKey("position_part.id_position_part"))
    fitment_notes = Column(Text)
    created_at = Column(DateTime, default=datetime.utcnow)

    model_year_engine = relationship("ModelYearEngine")
    part = relationship("Part")
    position = relationship("PositionPart")

    __table_args__ = (
        UniqueConstraint("model_year_engine_id", "part_id", "id_position_part",
                         name="uq_vehicle_part"),
        Index("idx_vehicle_parts_mye", "model_year_engine_id"),
        Index("idx_vehicle_parts_part", "part_id"),
    )


class Manufacturer(Base):
    __tablename__ = "manufacturers"
    id_manufacture = Column(Integer, primary_key=True)
    name_manufacture = Column(String(200), nullable=False, unique=True)
    id_type_manu = Column(Integer, ForeignKey("manufacture_type.id_type_manu"))
    id_quality_tier = Column(Integer, ForeignKey("quality_tier.id_quality_tier"))
    id_country = Column(Integer, ForeignKey("countries.id_country"))
    logo_url = Column(String(500))
    website = Column(String(500))
    created_at = Column(DateTime, default=datetime.utcnow)

    manufacture_type = relationship("ManufactureType")
    quality_tier = relationship("QualityTier")
    country = relationship("Country")


class AftermarketPart(Base):
    __tablename__ = "aftermarket_parts"
    id_aftermarket_parts = Column(Integer, primary_key=True)
    oem_part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False)
    manufacturer_id = Column(Integer, ForeignKey("manufacturers.id_manufacture"), nullable=False)
    part_number = Column(String(100), nullable=False)
    name_aftermarket_parts = Column(String(300))
    name_es = Column(String(300))
    id_quality_tier = Column(Integer, ForeignKey("quality_tier.id_quality_tier"))
    price_usd = Column(Float)
    warranty_months = Column(Integer)
    created_at = Column(DateTime, default=datetime.utcnow)

    oem_part = relationship("Part")
    manufacturer = relationship("Manufacturer")
    quality_tier = relationship("QualityTier")

    __table_args__ = (
        Index("idx_aftermarket_oem", "oem_part_id"),
        Index("idx_aftermarket_manufacturer", "manufacturer_id"),
        Index("idx_aftermarket_part_number", "part_number"),
    )


class PartCrossReference(Base):
    __tablename__ = "part_cross_references"
    id_part_cross_ref = Column(Integer, primary_key=True)
    part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False)
    cross_reference_number = Column(String(100), nullable=False)
    id_ref_type = Column(Integer, ForeignKey("reference_type.id_ref_type"))
    source_ref = Column(String(200))
    notes = Column(Text)
    created_at = Column(DateTime, default=datetime.utcnow)

    part = relationship("Part")
    reference_type = relationship("ReferenceType")

    __table_args__ = (
        Index("idx_cross_ref_part", "part_id"),
        Index("idx_cross_ref_number", "cross_reference_number"),
    )


class Diagram(Base):
    __tablename__ = "diagrams"
    id_diagram = Column(Integer, primary_key=True)
    name_diagram = Column(String(300), nullable=False)
    name_es = Column(String(300))
    group_id = Column(Integer, ForeignKey("part_groups.id_part_group"), nullable=False)
    image_path = Column(String(500), nullable=False)
    thumbnail_path = Column(String(500))
    display_order = Column(Integer, default=0)
    source_diagram = Column(String(200))
    created_at = Column(DateTime, default=datetime.utcnow)

    group = relationship("PartGroup")

    __table_args__ = (
        Index("idx_diagrams_group", "group_id"),
    )


class VehicleDiagram(Base):
    __tablename__ = "vehicle_diagrams"
    id_vehicle_dgr = Column(Integer, primary_key=True)
    diagram_id = Column(Integer, ForeignKey("diagrams.id_diagram"), nullable=False)
    model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye"), nullable=False)
    notes = Column(Text)
    created_at = Column(DateTime, default=datetime.utcnow)

    diagram = relationship("Diagram")
    model_year_engine = relationship("ModelYearEngine")

    __table_args__ = (
        UniqueConstraint("diagram_id", "model_year_engine_id", name="uq_vehicle_diagram"),
        Index("idx_vehicle_diagrams_diagram", "diagram_id"),
        Index("idx_vehicle_diagrams_mye", "model_year_engine_id"),
    )


class DiagramHotspot(Base):
    __tablename__ = "diagram_hotspots"
    id_dgr_hotspot = Column(Integer, primary_key=True)
    diagram_id = Column(Integer, ForeignKey("diagrams.id_diagram"), nullable=False)
    part_id = Column(Integer, ForeignKey("parts.id_part"))
    callout_number = Column(Integer)
    id_shape = Column(Integer, ForeignKey("shapes.id_shape"))
    coords = Column(Text, nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)

    diagram = relationship("Diagram")
    part = relationship("Part")
    shape = relationship("Shape")

    __table_args__ = (
        Index("idx_hotspots_diagram", "diagram_id"),
        Index("idx_hotspots_part", "part_id"),
    )


class VinCache(Base):
    __tablename__ = "vin_cache"
    id = Column(Integer, primary_key=True)
    vin = Column(String(17), nullable=False, unique=True)
    decoded_data = Column(JSONB, nullable=False)
    make = Column(String(100))
    model = Column(String(100))
    year = Column(Integer)
    engine_info = Column(String(200))
    body_class = Column(String(100))
    drive_type = Column(String(100))
    model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye"))
    created_at = Column(DateTime, default=datetime.utcnow)
    expires_at = Column(DateTime)

    __table_args__ = (
        Index("idx_vin_cache_vin", "vin"),
        Index("idx_vin_cache_make_model", "make", "model", "year"),
    )


# ─────────────────────────────────────────────
# Full-text search trigger SQL (run after table creation)
# ─────────────────────────────────────────────

SEARCH_VECTOR_TRIGGER_SQL = """
CREATE OR REPLACE FUNCTION parts_search_vector_update() RETURNS trigger AS $$
BEGIN
    NEW.search_vector := to_tsvector('spanish',
        coalesce(NEW.oem_part_number, '') || ' ' ||
        coalesce(NEW.name_part, '') || ' ' ||
        coalesce(NEW.name_es, '') || ' ' ||
        coalesce(NEW.description, '')
    );
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_parts_search_vector ON parts;
CREATE TRIGGER trg_parts_search_vector
    BEFORE INSERT OR UPDATE ON parts
    FOR EACH ROW
    EXECUTE FUNCTION parts_search_vector_update();
"""
