# ================================================================
# services/procurement/app/models/purchase_order.py
# ================================================================
"""
Purchase Order Models
Migrated from Suppliers Service - Now owned by Procurement Service
"""

import uuid
import enum
from datetime import datetime, timezone
from decimal import Decimal
from sqlalchemy import Column, String, DateTime, Float, Integer, Text, Index, Boolean, Numeric, ForeignKey, Enum as SQLEnum
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy.orm import relationship, deferred
from sqlalchemy.sql import func

from shared.database.base import Base


class PurchaseOrderStatus(enum.Enum):
    """Purchase order lifecycle status"""
    draft = "draft"
    pending_approval = "pending_approval"
    approved = "approved"
    sent_to_supplier = "sent_to_supplier"
    confirmed = "confirmed"
    partially_received = "partially_received"
    completed = "completed"
    cancelled = "cancelled"
    disputed = "disputed"


class DeliveryStatus(enum.Enum):
    """Delivery status tracking"""
    scheduled = "scheduled"
    in_transit = "in_transit"
    out_for_delivery = "out_for_delivery"
    delivered = "delivered"
    partially_delivered = "partially_delivered"
    failed_delivery = "failed_delivery"
    returned = "returned"


class QualityRating(enum.Enum):
    """Quality rating scale"""
    excellent = 5
    good = 4
    average = 3
    poor = 2
    very_poor = 1


class InvoiceStatus(enum.Enum):
    """Invoice processing status"""
    pending = "pending"
    approved = "approved"
    paid = "paid"
    overdue = "overdue"
    disputed = "disputed"
    cancelled = "cancelled"


class PurchaseOrder(Base):
    """Purchase orders to suppliers - Core procurement execution"""
    __tablename__ = "purchase_orders"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    supplier_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # Reference to Suppliers Service

    # Order identification
    po_number = Column(String(50), nullable=False, unique=True, index=True)  # Human-readable PO number
    reference_number = Column(String(100), nullable=True)  # Internal reference

    # Link to procurement plan
    procurement_plan_id = Column(UUID(as_uuid=True), nullable=True, index=True)  # Link to ProcurementPlan

    # Order status and workflow
    status = Column(SQLEnum(PurchaseOrderStatus), nullable=False, default=PurchaseOrderStatus.draft, index=True)
    priority = Column(String(20), nullable=False, default="normal")  # urgent, high, normal, low

    # Order details
    order_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))
    required_delivery_date = Column(DateTime(timezone=True), nullable=True)  # Stored as DateTime for consistency
    estimated_delivery_date = Column(DateTime(timezone=True), nullable=True)
    expected_delivery_date = Column(DateTime(timezone=True), nullable=True)  # When delivery is actually expected (used for dashboard tracking)

    # Financial information
    subtotal = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    tax_amount = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    shipping_cost = Column(Numeric(10, 2), nullable=False, default=Decimal("0.00"))
    discount_amount = Column(Numeric(10, 2), nullable=False, default=Decimal("0.00"))
    total_amount = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    currency = Column(String(3), nullable=False, default="EUR")

    # Delivery information
    delivery_address = Column(Text, nullable=True)  # Override default address
    delivery_instructions = Column(Text, nullable=True)
    delivery_contact = Column(String(200), nullable=True)
    delivery_phone = Column(String(30), nullable=True)

    # Approval workflow
    requires_approval = Column(Boolean, nullable=False, default=False)
    approved_by = Column(UUID(as_uuid=True), nullable=True)
    approved_at = Column(DateTime(timezone=True), nullable=True)
    rejection_reason = Column(Text, nullable=True)

    # Auto-approval tracking
    auto_approved = Column(Boolean, nullable=False, default=False)  # Whether this was auto-approved
    auto_approval_rule_id = Column(UUID(as_uuid=True), nullable=True)  # Which rule approved it

    # Communication tracking
    sent_to_supplier_at = Column(DateTime(timezone=True), nullable=True)
    supplier_confirmation_date = Column(DateTime(timezone=True), nullable=True)
    supplier_reference = Column(String(100), nullable=True)  # Supplier's order reference

    # Additional information
    notes = Column(Text, nullable=True)
    internal_notes = Column(Text, nullable=True)  # Not shared with supplier
    terms_and_conditions = Column(Text, nullable=True)

    # JTBD Dashboard: Structured reasoning data for i18n support
    # Backend stores structured data, frontend translates using i18n
    reasoning_data = Column(JSONB, nullable=True)  # Structured reasoning data for multilingual support
    # reasoning_data structure (see shared/schemas/reasoning_types.py):
    # {
    #   "type": "low_stock_detection" | "forecast_demand" | "safety_stock_replenishment" | etc.,
    #   "parameters": {
    #     "supplier_name": "Harinas del Norte",
    #     "product_names": ["Flour Type 55", "Flour Type 45"],
    #     "days_until_stockout": 3,
    #     "current_stock": 45.5,
    #     "required_stock": 200
    #   },
    #   "consequence": {
    #     "type": "stockout_risk",
    #     "severity": "high",
    #     "impact_days": 3,
    #     "affected_products": ["Baguette", "Croissant"]
    #   },
    #   "metadata": {
    #     "trigger_source": "orchestrator_auto",
    #     "forecast_confidence": 0.85,
    #     "ai_assisted": true
    #   }
    # }

    # Internal transfer fields (for enterprise parent-child transfers)
    is_internal = Column(Boolean, default=False, nullable=False, index=True)  # Flag for internal transfers
    source_tenant_id = Column(UUID(as_uuid=True), nullable=True, index=True)  # Parent tenant for internal transfers
    destination_tenant_id = Column(UUID(as_uuid=True), nullable=True, index=True)  # Child tenant for internal transfers
    transfer_type = Column(String(50), nullable=True)  # finished_goods, raw_materials

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
    created_by = Column(UUID(as_uuid=True), nullable=False)
    updated_by = Column(UUID(as_uuid=True), nullable=False)

    # Relationships
    items = relationship("PurchaseOrderItem", back_populates="purchase_order", cascade="all, delete-orphan")
    deliveries = relationship("Delivery", back_populates="purchase_order", cascade="all, delete-orphan")
    invoices = relationship("SupplierInvoice", back_populates="purchase_order", cascade="all, delete-orphan")

    # Indexes
    __table_args__ = (
        Index('ix_purchase_orders_tenant_supplier', 'tenant_id', 'supplier_id'),
        Index('ix_purchase_orders_tenant_status', 'tenant_id', 'status'),
        Index('ix_purchase_orders_tenant_plan', 'tenant_id', 'procurement_plan_id'),
        Index('ix_purchase_orders_order_date', 'order_date'),
        Index('ix_purchase_orders_delivery_date', 'required_delivery_date'),
    )


class PurchaseOrderItem(Base):
    """Individual items within purchase orders"""
    __tablename__ = "purchase_order_items"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id', ondelete='CASCADE'), nullable=False, index=True)

    # Link to procurement requirement
    procurement_requirement_id = Column(UUID(as_uuid=True), nullable=True, index=True)  # Link to ProcurementRequirement

    # Product identification (references Inventory Service)
    inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    product_code = Column(String(100), nullable=True)  # Supplier's product code
    product_name = Column(String(200), nullable=False)  # Denormalized for convenience

    # Supplier price list reference (from Suppliers Service)
    supplier_price_list_id = Column(UUID(as_uuid=True), nullable=True, index=True)

    # Order quantities
    ordered_quantity = Column(Numeric(12, 3), nullable=False)
    unit_of_measure = Column(String(20), nullable=False)
    unit_price = Column(Numeric(10, 4), nullable=False)
    line_total = Column(Numeric(12, 2), nullable=False)

    # Delivery tracking
    received_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))
    remaining_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))

    # Quality and notes
    quality_requirements = Column(Text, nullable=True)
    item_notes = Column(Text, nullable=True)

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)

    # Relationships
    purchase_order = relationship("PurchaseOrder", back_populates="items")
    delivery_items = relationship("DeliveryItem", back_populates="purchase_order_item", cascade="all, delete-orphan")

    # Indexes
    __table_args__ = (
        Index('ix_po_items_tenant_po', 'tenant_id', 'purchase_order_id'),
        Index('ix_po_items_inventory_product', 'inventory_product_id'),
        Index('ix_po_items_requirement', 'procurement_requirement_id'),
    )


class Delivery(Base):
    """Delivery tracking for purchase orders"""
    __tablename__ = "deliveries"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id', ondelete='CASCADE'), nullable=False, index=True)
    supplier_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # Reference to Suppliers Service

    # Delivery identification
    delivery_number = Column(String(50), nullable=False, unique=True, index=True)
    supplier_delivery_note = Column(String(100), nullable=True)  # Supplier's delivery reference

    # Delivery status and tracking
    status = Column(SQLEnum(DeliveryStatus), nullable=False, default=DeliveryStatus.scheduled, index=True)

    # Scheduling and timing
    scheduled_date = Column(DateTime(timezone=True), nullable=True)
    estimated_arrival = Column(DateTime(timezone=True), nullable=True)
    actual_arrival = Column(DateTime(timezone=True), nullable=True)
    completed_at = Column(DateTime(timezone=True), nullable=True)

    # Delivery details
    delivery_address = Column(Text, nullable=True)
    delivery_contact = Column(String(200), nullable=True)
    delivery_phone = Column(String(30), nullable=True)
    carrier_name = Column(String(200), nullable=True)
    tracking_number = Column(String(100), nullable=True)

    # Quality inspection
    inspection_passed = Column(Boolean, nullable=True)
    inspection_notes = Column(Text, nullable=True)
    quality_issues = Column(JSONB, nullable=True)  # Documented quality problems

    # Received by information
    received_by = Column(UUID(as_uuid=True), nullable=True)  # User who received the delivery
    received_at = Column(DateTime(timezone=True), nullable=True)

    # Additional information
    notes = Column(Text, nullable=True)
    photos = Column(JSONB, nullable=True)  # Photo URLs for documentation

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
    created_by = Column(UUID(as_uuid=True), nullable=False)

    # Relationships
    purchase_order = relationship("PurchaseOrder", back_populates="deliveries")
    items = relationship("DeliveryItem", back_populates="delivery", cascade="all, delete-orphan")

    # Indexes
    __table_args__ = (
        Index('ix_deliveries_tenant_status', 'tenant_id', 'status'),
        Index('ix_deliveries_scheduled_date', 'scheduled_date'),
        Index('ix_deliveries_tenant_po', 'tenant_id', 'purchase_order_id'),
    )


class DeliveryItem(Base):
    """Individual items within deliveries"""
    __tablename__ = "delivery_items"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    delivery_id = Column(UUID(as_uuid=True), ForeignKey('deliveries.id', ondelete='CASCADE'), nullable=False, index=True)
    purchase_order_item_id = Column(UUID(as_uuid=True), ForeignKey('purchase_order_items.id', ondelete='CASCADE'), nullable=False, index=True)

    # Product identification
    inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True)

    # Delivery quantities
    ordered_quantity = Column(Numeric(12, 3), nullable=False)
    delivered_quantity = Column(Numeric(12, 3), nullable=False)
    accepted_quantity = Column(Numeric(12, 3), nullable=False)
    rejected_quantity = Column(Numeric(12, 3), nullable=False, default=Decimal("0.000"))

    # Quality information
    batch_lot_number = Column(String(100), nullable=True)
    expiry_date = Column(DateTime(timezone=True), nullable=True)
    quality_grade = Column(String(20), nullable=True)

    # Issues and notes
    quality_issues = Column(Text, nullable=True)
    rejection_reason = Column(Text, nullable=True)
    item_notes = Column(Text, nullable=True)

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)

    # Relationships
    delivery = relationship("Delivery", back_populates="items")
    purchase_order_item = relationship("PurchaseOrderItem", back_populates="delivery_items")

    # Indexes
    __table_args__ = (
        Index('ix_delivery_items_tenant_delivery', 'tenant_id', 'delivery_id'),
        Index('ix_delivery_items_inventory_product', 'inventory_product_id'),
    )


class SupplierInvoice(Base):
    """Invoices from suppliers"""
    __tablename__ = "supplier_invoices"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
    supplier_id = Column(UUID(as_uuid=True), nullable=False, index=True)  # Reference to Suppliers Service
    purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id', ondelete='SET NULL'), nullable=True, index=True)

    # Invoice identification
    invoice_number = Column(String(50), nullable=False, unique=True, index=True)
    supplier_invoice_number = Column(String(100), nullable=False)

    # Invoice status and dates
    status = Column(SQLEnum(InvoiceStatus), nullable=False, default=InvoiceStatus.pending, index=True)
    invoice_date = Column(DateTime(timezone=True), nullable=False)
    due_date = Column(DateTime(timezone=True), nullable=False)
    received_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))

    # Financial information
    subtotal = Column(Numeric(12, 2), nullable=False)
    tax_amount = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    shipping_cost = Column(Numeric(10, 2), nullable=False, default=Decimal("0.00"))
    discount_amount = Column(Numeric(10, 2), nullable=False, default=Decimal("0.00"))
    total_amount = Column(Numeric(12, 2), nullable=False)
    currency = Column(String(3), nullable=False, default="EUR")

    # Payment tracking
    paid_amount = Column(Numeric(12, 2), nullable=False, default=Decimal("0.00"))
    payment_date = Column(DateTime(timezone=True), nullable=True)
    payment_reference = Column(String(100), nullable=True)

    # Invoice validation
    approved_by = Column(UUID(as_uuid=True), nullable=True)
    approved_at = Column(DateTime(timezone=True), nullable=True)
    rejection_reason = Column(Text, nullable=True)

    # Additional information
    notes = Column(Text, nullable=True)
    invoice_document_url = Column(String(500), nullable=True)  # PDF storage location

    # Audit fields
    created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
    updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
    created_by = Column(UUID(as_uuid=True), nullable=False)

    # Relationships
    purchase_order = relationship("PurchaseOrder", back_populates="invoices")

    # Indexes
    __table_args__ = (
        Index('ix_invoices_tenant_supplier', 'tenant_id', 'supplier_id'),
        Index('ix_invoices_tenant_status', 'tenant_id', 'status'),
        Index('ix_invoices_due_date', 'due_date'),
    )
