"""Modèles C4 : contrats photocopieurs et stock de consommables partagé."""
from datetime import datetime, timezone

from ...extensions import db


class PhotocopierContract(db.Model):
    __tablename__ = "photocopier_contracts"

    id = db.Column(db.Integer, primary_key=True)
    supplier_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=False, index=True)
    name = db.Column(db.String(200), nullable=False)
    reference = db.Column(db.String(120), nullable=True)
    start_date = db.Column(db.Date, nullable=False)
    end_date = db.Column(db.Date, nullable=False)
    quota_start_date = db.Column(db.Date, nullable=True)
    anniversary_month = db.Column(db.Integer, nullable=False)
    anniversary_day = db.Column(db.Integer, nullable=False)
    status = db.Column(db.String(20), nullable=False, default="ACTIVE", index=True)
    notes = db.Column(db.Text, nullable=True)
    created_at = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    closed_at = db.Column(db.Date, nullable=True)

    supplier = db.relationship("Company")
    periods = db.relationship("PhotocopierContractPeriod", back_populates="contract", cascade="all, delete-orphan", order_by="PhotocopierContractPeriod.start_date")
    assignments = db.relationship("ContractEquipmentAssignment", back_populates="contract", cascade="all, delete-orphan")


class PhotocopierContractPeriod(db.Model):
    __tablename__ = "photocopier_contract_periods"
    __table_args__ = (
        db.UniqueConstraint("contract_id", "start_date", name="uq_c4_contract_period_start"),
        db.CheckConstraint("end_date >= start_date", name="ck_c4_period_dates"),
        db.CheckConstraint("(quota_bw IS NULL OR quota_bw >= 0) AND (quota_color IS NULL OR quota_color >= 0)", name="ck_c4_period_quotas"),
    )

    id = db.Column(db.Integer, primary_key=True)
    contract_id = db.Column(db.Integer, db.ForeignKey("photocopier_contracts.id", ondelete="CASCADE"), nullable=False, index=True)
    start_date = db.Column(db.Date, nullable=False, index=True)
    end_date = db.Column(db.Date, nullable=False, index=True)
    quota_bw = db.Column(db.Integer, nullable=True)
    quota_color = db.Column(db.Integer, nullable=True)
    bw_included_unit_price = db.Column(db.Numeric(12, 6), nullable=True)
    bw_overage_unit_price = db.Column(db.Numeric(12, 6), nullable=True)
    color_included_unit_price = db.Column(db.Numeric(12, 6), nullable=True)
    color_overage_unit_price = db.Column(db.Numeric(12, 6), nullable=True)
    status = db.Column(db.String(20), nullable=False, default="OPEN")

    contract = db.relationship("PhotocopierContract", back_populates="periods")


class ContractEquipmentAssignment(db.Model):
    __tablename__ = "contract_equipment_assignments"
    __table_args__ = (
        db.UniqueConstraint("contract_id", "equipment_id", "entry_date", name="uq_c4_contract_equipment_entry"),
        db.CheckConstraint("exit_date IS NULL OR exit_date >= entry_date", name="ck_c4_assignment_dates"),
    )

    id = db.Column(db.Integer, primary_key=True)
    contract_id = db.Column(db.Integer, db.ForeignKey("photocopier_contracts.id", ondelete="CASCADE"), nullable=False, index=True)
    equipment_id = db.Column(db.Integer, db.ForeignKey("equipments.id", ondelete="CASCADE"), nullable=False, index=True)
    entry_date = db.Column(db.Date, nullable=False)
    exit_date = db.Column(db.Date, nullable=True)
    replacement_reason = db.Column(db.String(40), nullable=True)
    replacement_comment = db.Column(db.Text, nullable=True)

    contract = db.relationship("PhotocopierContract", back_populates="assignments")
    equipment = db.relationship("Equipment")


class ConsumableOrder(db.Model):
    __tablename__ = "consumable_orders"
    __table_args__ = (
        db.CheckConstraint("quantity_ordered > 0", name="ck_c4_order_quantity"),
        db.CheckConstraint("quantity_received >= 0 AND quantity_received <= quantity_ordered", name="ck_c4_order_received"),
    )

    id = db.Column(db.Integer, primary_key=True)
    consumable_id = db.Column(db.Integer, db.ForeignKey("consumables.id", ondelete="RESTRICT"), nullable=False, index=True)
    supplier_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True, index=True)
    quantity_ordered = db.Column(db.Integer, nullable=False)
    quantity_received = db.Column(db.Integer, nullable=False, default=0)
    status = db.Column(db.String(30), nullable=False, default="TO_ORDER", index=True)
    ordered_at = db.Column(db.DateTime, nullable=True)
    received_at = db.Column(db.DateTime, nullable=True)
    comment = db.Column(db.Text, nullable=True)
    created_by_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    cancelled_at = db.Column(db.DateTime, nullable=True)
    cancelled_by_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    cancellation_reason = db.Column(db.Text, nullable=True)

    consumable = db.relationship("Consumable")
    supplier = db.relationship("Company")
    created_by = db.relationship("User", foreign_keys=[created_by_id])
    cancelled_by = db.relationship("User", foreign_keys=[cancelled_by_id])
    receipts = db.relationship("ConsumableReceipt", back_populates="order", cascade="all, delete-orphan")

    @property
    def remaining_quantity(self):
        return max((self.quantity_ordered or 0) - (self.quantity_received or 0), 0)


class ConsumableReceipt(db.Model):
    __tablename__ = "consumable_receipts"

    id = db.Column(db.Integer, primary_key=True)
    order_id = db.Column(db.Integer, db.ForeignKey("consumable_orders.id", ondelete="CASCADE"), nullable=False, index=True)
    quantity = db.Column(db.Integer, nullable=False)
    received_at = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(timezone.utc))
    received_by_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    comment = db.Column(db.Text, nullable=True)

    order = db.relationship("ConsumableOrder", back_populates="receipts")
    received_by = db.relationship("User")
