import uuid
import enum
from datetime import datetime
from decimal import Decimal
from sqlalchemy import String, DateTime, Enum as SAEnum, ForeignKey, Text, Integer, Boolean, Numeric
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.database import Base


class OrderStatus(str, enum.Enum):
    draft = "draft"
    submitted = "submitted"
    processing = "processing"
    completed = "completed"
    rejected = "rejected"


class Order(Base):
    __tablename__ = "orders"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    order_number: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
    template_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("templates.id"), nullable=True)
    status: Mapped[OrderStatus] = mapped_column(SAEnum(OrderStatus), default=OrderStatus.draft, nullable=False)
    created_by: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
    source_excel: Mapped[str] = mapped_column(String(1000), nullable=True)
    notes: Mapped[str] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    submitted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    processing_started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    rejected_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    estimated_price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2), nullable=True)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True, index=True
    )

    template: Mapped["Template"] = relationship("Template", back_populates="orders")
    created_by_user: Mapped["User"] = relationship("User", back_populates="orders", foreign_keys=[created_by])
    tenant: Mapped["Tenant | None"] = relationship("Tenant", back_populates="orders", lazy="noload")
    items: Mapped[list["OrderItem"]] = relationship("OrderItem", back_populates="order", cascade="all, delete-orphan")
    lines: Mapped[list["OrderLine"]] = relationship(
        "OrderLine", back_populates="order", cascade="all, delete-orphan"
    )


class ItemStatus(str, enum.Enum):
    pending = "pending"
    approved = "approved"
    rejected = "rejected"


class AIValidationStatus(str, enum.Enum):
    not_started = "not_started"
    pending = "pending"
    completed = "completed"
    failed = "failed"


class OrderItem(Base):
    __tablename__ = "order_items"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    order_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("orders.id"), nullable=False)
    row_index: Mapped[int] = mapped_column(Integer, nullable=False)

    # 11 Standard fields (columns 0-10, skip col 5)
    ebene1: Mapped[str] = mapped_column(String(500), nullable=True)
    ebene2: Mapped[str] = mapped_column(String(500), nullable=True)
    baureihe: Mapped[str] = mapped_column(String(500), nullable=True)
    pim_id: Mapped[str] = mapped_column(String(500), nullable=True)
    produkt_baureihe: Mapped[str] = mapped_column(String(500), nullable=True)
    # col 5 is skipped (separator)
    gewaehltes_produkt: Mapped[str] = mapped_column(String(500), nullable=True)
    name_cad_modell: Mapped[str] = mapped_column(String(500), nullable=True)
    gewuenschte_bildnummer: Mapped[str] = mapped_column(String(500), nullable=True)
    lagertyp: Mapped[str] = mapped_column(String(500), nullable=True)
    medias_rendering: Mapped[bool] = mapped_column(Boolean, nullable=True)

    # Component pairs (cols 11+): [{part_name, material, component_type, column_index}]
    components: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)

    # CAD linkage
    cad_file_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("cad_files.id"), nullable=True)
    thumbnail_path: Mapped[str] = mapped_column(String(1000), nullable=True)
    # Material assignments per CAD part: [{part_name, material}]
    cad_part_materials: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)

    # AI validation
    ai_validation_status: Mapped[AIValidationStatus] = mapped_column(
        SAEnum(AIValidationStatus), default=AIValidationStatus.not_started, nullable=False
    )
    ai_validation_result: Mapped[dict] = mapped_column(JSONB, nullable=True)

    item_status: Mapped[ItemStatus] = mapped_column(SAEnum(ItemStatus), default=ItemStatus.pending, nullable=False)
    notes: Mapped[str] = mapped_column(Text, nullable=True)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True, index=True
    )
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)

    order: Mapped["Order"] = relationship("Order", back_populates="items")
    cad_file: Mapped["CadFile"] = relationship("CadFile", back_populates="order_items")

    @property
    def cad_parsed_objects(self) -> list[str] | None:
        """Part names extracted from the linked STEP file, for Pydantic serialization."""
        if self.cad_file and self.cad_file.parsed_objects:
            return self.cad_file.parsed_objects.get("objects") or []
        return None


class OrderLine(Base):
    __tablename__ = "order_lines"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    order_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("orders.id", ondelete="CASCADE"), nullable=False, index=True
    )
    product_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("products.id"), nullable=False, index=True
    )
    output_type_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("output_types.id"), nullable=True
    )
    gewuenschte_bildnummer: Mapped[str | None] = mapped_column(String(500), nullable=True)
    item_status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
    render_status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
    result_path: Mapped[str | None] = mapped_column(String(1000), nullable=True)
    render_log: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
    ai_validation_status: Mapped[str] = mapped_column(String(20), nullable=False, default="not_started")
    ai_validation_result: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
    flamenco_job_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
    render_backend_used: Mapped[str | None] = mapped_column(String(20), nullable=True)
    render_started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    render_completed_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    unit_price: Mapped[Decimal | None] = mapped_column(Numeric(10, 2), nullable=True)
    render_position_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("product_render_positions.id", ondelete="SET NULL"),
        nullable=True,
    )
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    tenant_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True, index=True
    )
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
    updated_at: Mapped[datetime] = mapped_column(
        DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False
    )

    order: Mapped["Order"] = relationship("Order", back_populates="lines")
    product: Mapped["Product"] = relationship("Product", back_populates="order_lines")
    output_type: Mapped["OutputType | None"] = relationship("OutputType", back_populates="order_lines")
    render_position: Mapped["ProductRenderPosition | None"] = relationship(
        "ProductRenderPosition", back_populates="order_lines"
    )
