"""
Modèle Maintenance - GMAO Collège
Gestion des interventions et maintenance
Compatible avec la base de données existante
"""
from datetime import datetime, timezone
from ...extensions import db


lot_task_equipments = db.Table(
    "lot_task_equipments",
    db.Column("lot_task_id", db.Integer, db.ForeignKey("lot_tasks.id", ondelete="CASCADE"), primary_key=True),
    db.Column("equipment_id", db.Integer, db.ForeignKey("equipments.id", ondelete="CASCADE"), primary_key=True),
)


class Intervention(db.Model):
    """Intervention de maintenance - compatible avec la base existante."""
    __tablename__ = "interventions"
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(300), nullable=False)
    description = db.Column(db.Text, default="")
    
    # Type : curatif (panne) ou préventif (maintenance planifiée)
    type = db.Column(db.String(20), nullable=False, default="curatif")
    preventive_type = db.Column(db.String(50), nullable=True)
    
    # Priorité
    priority = db.Column(db.String(20), default="normale")
    
    # Statut & Workflow
    status = db.Column(db.String(30), default="brouillon")
    workflow_type = db.Column(db.String(20), nullable=False, default="corrective", index=True)
    
    # Responsable actuel (qui doit agir maintenant)
    assigned_to_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    
    # Technicien assigné à l'exécution
    technician_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    
    # GIMA
    gima_number = db.Column(db.String(50), nullable=True)
    gima_service = db.Column(db.String(20), nullable=True)
    
    # Budget prévisionnel
    needs_budget = db.Column(db.Boolean, default=False)
    budget_approved = db.Column(db.Boolean, default=False)
    budget_amount = db.Column(db.Float, nullable=True)
    
    # Entreprise extérieure
    company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True)

    # Workflow travaux intégré à l'intervention
    execution_mode = db.Column(db.String(30), nullable=False, default="interne")
    department_service_id = db.Column(db.Integer, db.ForeignKey("services.id"), nullable=True)
    department_request_date = db.Column(db.Date, nullable=True)
    chief_validation_date = db.Column(db.Date, nullable=True)
    department_validation_date = db.Column(db.Date, nullable=True)
    quote_status = db.Column(db.String(30), nullable=False, default="non_requis")
    quote_reference = db.Column(db.String(100), nullable=True)
    quote_amount_ht = db.Column(db.Float, nullable=True)
    quote_amount_ttc = db.Column(db.Float, nullable=True)
    quote_date = db.Column(db.Date, nullable=True)
    quote_valid_until = db.Column(db.Date, nullable=True)
    work_notes = db.Column(db.Text, nullable=True)
    
    # Équipement
    equipment_id = db.Column(db.Integer, db.ForeignKey("equipments.id"), nullable=True)
    
    # Salle
    room_id = db.Column(db.Integer, db.ForeignKey("rooms.id"), nullable=True)
    
    # Quantité affectée (pour équipements multiples)
    quantity_affected = db.Column(db.Integer, nullable=True)
    individual_numbers = db.Column(db.Text, nullable=True)
    
    # Dates
    requested_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    started_at = db.Column(db.DateTime, nullable=True)
    completed_at = db.Column(db.DateTime, nullable=True)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc),
                           onupdate=lambda: datetime.now(timezone.utc))
    
    # Récurrence
    recurrence_month = db.Column(db.Integer, nullable=True)
    frequency_days = db.Column(db.Integer, nullable=True)
    next_due_date = db.Column(db.DateTime, nullable=True)
    is_recurring = db.Column(db.Boolean, default=False)
    
    # Coût & Temps
    cost = db.Column(db.Float, nullable=True, default=0.0)
    time_spent = db.Column(db.Integer, nullable=True)
    
    # Demandeur externe
    requester_name = db.Column(db.String(150), nullable=True)
    requester_contact = db.Column(db.String(200), nullable=True)
    
    # Suppression logique
    is_deleted = db.Column(db.Boolean, default=False)
    deleted_at = db.Column(db.DateTime, nullable=True)
    deleted_by_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    refusal_reason = db.Column(db.Text, nullable=True)
    refused_at = db.Column(db.DateTime, nullable=True)
    refused_by_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    
    # ENT
    ent_message_id = db.Column(db.String(100), nullable=True)
    ent_sender = db.Column(db.String(200), nullable=True)
    
    # Lot
    lot_id = db.Column(db.Integer, db.ForeignKey("lots.id"), nullable=True)
    
    # Colonnes additionnelles
    author_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    scheduled_date = db.Column(db.Date, nullable=True)
    scheduled_start = db.Column(db.Time, nullable=True)
    scheduled_end = db.Column(db.Time, nullable=True)
    completed_date = db.Column(db.Date, nullable=True)
    estimated_duration = db.Column(db.Float, nullable=True)
    actual_duration = db.Column(db.Float, nullable=True)
    notes = db.Column(db.Text, nullable=True)
    
    # Reports
    original_scheduled_date = db.Column(db.DateTime, nullable=True)
    postpone_count = db.Column(db.Integer, default=0)
    last_postpone_reason = db.Column(db.Text, nullable=True)
    last_postpone_at = db.Column(db.DateTime, nullable=True)
    
    # Champs migrés depuis ScheduledTask (fusion)
    preventive_task_id = db.Column(db.Integer, db.ForeignKey("preventive_tasks.id"), nullable=True)
    lot_task_id = db.Column(db.Integer, db.ForeignKey("lot_tasks.id"), nullable=True)
    postpone_reason = db.Column(db.Text, nullable=True)
    
    # Relations
    parts_used = db.relationship("InterventionPart", backref="intervention",
                                 cascade="all, delete-orphan", lazy="dynamic")
    comments = db.relationship("InterventionComment", backref="intervention",
                               cascade="all, delete-orphan", lazy="dynamic")
    documents = db.relationship("InterventionDocument", backref="intervention",
                                cascade="all, delete-orphan", lazy="dynamic")
    status_history = db.relationship("StatusChange", backref="intervention",
                                      cascade="all, delete-orphan", lazy="dynamic")
    
    # User relations - utiliser foreign_keys pour éviter les conflits
    assigned_to = db.relationship("User", foreign_keys=[assigned_to_id])
    technician = db.relationship("User", foreign_keys=[technician_id])
    author = db.relationship("User", foreign_keys=[author_id])
    deleted_by = db.relationship("User", foreign_keys=[deleted_by_id])
    refused_by = db.relationship("User", foreign_keys=[refused_by_id])
    
    # Lot relation
    lot = db.relationship("Lot", backref="interventions_list")
    room = db.relationship("Room", foreign_keys=[room_id])
    preventive_task = db.relationship("PreventiveTask", foreign_keys=[preventive_task_id])
    lot_task = db.relationship("LotTask", foreign_keys=[lot_task_id])
    company = db.relationship("Company", foreign_keys=[company_id])
    department_service = db.relationship("Service", foreign_keys=[department_service_id])
    
    @property
    def status_color(self):
        """Couleur du badge de statut."""
        colors = {
            'brouillon': 'secondary',
            'planifiee': 'info',
            'en_attente': 'warning',
            'en_cours': 'primary',
            'en_attente_pieces': 'warning',
            'en_attente_entreprise': 'info',
            'terminee': 'success',
            'cloturee': 'dark',
            'annulee': 'danger',
            'ignoree': 'secondary',
            'refusee': 'danger',
            'attente_chef': 'warning', 'demande_departement': 'info',
            'attente_devis': 'orange', 'devis_a_valider': 'warning',
            'devis_accepte': 'success', 'entreprise_mandatee': 'info',
            'travaux_planifies': 'primary', 'travaux_en_cours': 'primary',
            'travaux_termines': 'success', 'reception': 'success',
        }
        return colors.get(self.status, 'secondary')

    @property
    def workflow_label(self):
        from app_new.constants import WORKFLOW_TYPES
        return WORKFLOW_TYPES.get(self.workflow_type, self.workflow_type or 'Corrective')
    
    @property
    def status_label(self):
        """Label du statut."""
        labels = {
            'brouillon': 'Brouillon',
            'planifiee': 'Planifiee',
            'en_attente': 'En attente',
            'en_cours': 'En cours',
            'en_attente_pieces': 'En attente pieces',
            'en_attente_entreprise': 'En attente entreprise',
            'terminee': 'Terminee',
            'cloturee': 'Cloturee',
            'annulee': 'Annulee',
            'ignoree': 'Ignoree',
            'refusee': 'Refusée',
            'attente_chef': 'Validation du chef', 'demande_departement': 'Demande au Département',
            'attente_devis': 'Devis attendu', 'devis_a_valider': 'Devis à valider',
            'devis_accepte': 'Devis accepté', 'entreprise_mandatee': 'Entreprise mandatée',
            'travaux_planifies': 'Travaux planifiés', 'travaux_en_cours': 'Travaux en cours',
            'travaux_termines': 'Travaux terminés', 'reception': 'Réception',
        }
        return labels.get(self.status, self.status)
    
    @property
    def priority_color(self):
        """Couleur du badge de priorité."""
        colors = {
            'basse': 'secondary',
            'normale': 'primary',
            'haute': 'warning',
            'urgente': 'danger',
        }
        return colors.get(self.priority, 'secondary')
    
    @property
    def priority_label(self):
        """Label de la priorité."""
        labels = {
            'basse': 'Basse',
            'normale': 'Normale',
            'haute': 'Haute',
            'urgente': 'Urgente',
        }
        return labels.get(self.priority, self.priority)
    
    @property
    def effective_estimated_duration(self):
        """Duree previsionnelle auto-adaptee.
        
        Si actual_duration existe (duree reelle), on l'utilise.
        Sinon si estimated_duration existe (duree manuelle), on l'utilise.
        Sinon on calcule la moyenne des durees reelles des interventions 
        passees sur le meme equipement + meme type.
        Sans durée connue, retourne 0 : le moteur signale alors « durée à
        renseigner » au lieu d'inventer une heure.
        """
        if self.actual_duration:
            return self.actual_duration
        if self.estimated_duration:
            return self.estimated_duration
        # Moyenne historique : interventions terminees sur le meme equipement + meme type
        from sqlalchemy import func
        avg = db.session.query(func.avg(Intervention.actual_duration)).filter(
            Intervention.equipment_id == self.equipment_id,
            Intervention.type == self.type,
            Intervention.actual_duration.isnot(None),
            Intervention.id != self.id
        ).scalar()
        if avg and avg > 0:
            return round(avg, 1)
        # Moyenne par lot + type
        if self.lot_id:
            avg_lot = db.session.query(func.avg(Intervention.actual_duration)).filter(
                Intervention.lot_id == self.lot_id,
                Intervention.type == self.type,
                Intervention.actual_duration.isnot(None),
                Intervention.id != self.id
            ).scalar()
            if avg_lot and avg_lot > 0:
                return round(avg_lot, 1)
        return 0
    
    @property
    def is_overdue(self):
        """True si l'intervention est en retard (date planifiee depassee et non terminee)."""
        if self.status in ('terminee', 'cloturee', 'annulee', 'ignoree'):
            return False
        if not self.scheduled_date:
            return False
        from datetime import date
        return self.scheduled_date < date.today()
    
    def can_be_ignored(self):
        return self.status == 'planifiee'
    
    def ignore(self, reason=''):
        """Marque l'intervention comme ignoree."""
        self.status = 'ignoree'
        self.postpone_reason = reason
        from ...extensions import db
        db.session.commit()
    
    @property
    def progress_label(self):
        """Label d'avancement selon le pourcentage."""
        if self.status in ('terminee', 'cloturee'):
            return 'Terminee'
        if self.status == 'annulee':
            return 'Annulee'
        if self.status == 'brouillon':
            return 'Brouillon'
        if self.status == 'en_cours':
            if not hasattr(self, '_progress') or self._progress is None:
                return 'En cours'
        return self.status_label
    
    def __repr__(self):
        return f"<Intervention #{self.id} {self.title}>"


class StatusChange(db.Model):
    """Historique des changements de statut."""
    __tablename__ = "status_changes"
    
    id = db.Column(db.Integer, primary_key=True)
    intervention_id = db.Column(db.Integer, db.ForeignKey("interventions.id"), nullable=False)
    from_status = db.Column(db.String(30), nullable=True)
    to_status = db.Column(db.String(30), nullable=False)
    changed_by_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    comment = db.Column(db.Text, default="")
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relations
    changed_by = db.relationship("User", backref="status_changes_list")

    @property
    def to_label(self):
        from app_new.constants import INTERVENTION_STATUSES
        return INTERVENTION_STATUSES.get(self.to_status, {}).get("label", self.to_status or "Statut inconnu")

    @property
    def from_label(self):
        from app_new.constants import INTERVENTION_STATUSES
        return INTERVENTION_STATUSES.get(self.from_status, {}).get("label", self.from_status or "Création")

    @property
    def to_color(self):
        from app_new.constants import INTERVENTION_STATUSES
        return INTERVENTION_STATUSES.get(self.to_status, {}).get("color", "secondary")
    
    def __repr__(self):
        return f"<StatusChange {self.from_status} → {self.to_status}>"


class InterventionComment(db.Model):
    """Commentaire sur une intervention."""
    __tablename__ = "intervention_comments"
    
    id = db.Column(db.Integer, primary_key=True)
    intervention_id = db.Column(db.Integer, db.ForeignKey("interventions.id"), nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relations
    author = db.relationship("User", backref="comments_list")
    
    def __repr__(self):
        return f"<InterventionComment {self.id}>"


class InterventionDocument(db.Model):
    """Document attaché à une intervention."""
    __tablename__ = "intervention_documents"
    
    id = db.Column(db.Integer, primary_key=True)
    intervention_id = db.Column(db.Integer, db.ForeignKey("interventions.id"), nullable=False)
    filename = db.Column(db.String(255), nullable=False)
    filepath = db.Column(db.String(500), nullable=False)
    description = db.Column(db.Text, nullable=True)
    document_type = db.Column(db.String(30), nullable=False, default="autre", index=True)
    uploaded_at = db.Column(db.DateTime, nullable=True)
    uploaded_by_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    
    # Relations
    uploader = db.relationship("User", foreign_keys=[uploaded_by_id])
    
    def __repr__(self):
        return f"<InterventionDocument {self.filename}>"


class InterventionPart(db.Model):
    """Pièce utilisée dans une intervention."""
    __tablename__ = "intervention_parts"
    
    id = db.Column(db.Integer, primary_key=True)
    intervention_id = db.Column(db.Integer, db.ForeignKey("interventions.id"), nullable=False)
    part_id = db.Column(db.Integer, db.ForeignKey("parts.id"), nullable=False)
    quantity = db.Column(db.Integer, nullable=False, default=1)
    
    # Relations - utiliser back_populates pour éviter conflit
    part = db.relationship("Part", back_populates="usages_list")
    
    def __repr__(self):
        return f"<InterventionPart {self.part_id}x{self.quantity}>"


class Lot(db.Model):
    """Lot de maintenance."""
    __tablename__ = "lots"
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(500), nullable=False)
    company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True)
    category_id = db.Column(db.Integer, db.ForeignKey("equipment_categories.id"), nullable=True)
    is_present = db.Column(db.Boolean, nullable=False, default=True)
    absence_reason = db.Column(db.String(500), nullable=True)
    
    # Relations
    category = db.relationship("EquipmentCategory", foreign_keys=[category_id])
    tasks = db.relationship("LotTask", backref="lot")

    @property
    def active_equipment_count(self):
        """Equipements relies directement au lot et encore dans le patrimoine."""
        from .equipment import Equipment
        return Equipment.query.filter(
            Equipment.lot_id == self.id,
            Equipment.is_deleted.is_(False),
            db.or_(Equipment.status.is_(None), Equipment.status != 'jete'),
        ).count()

    @property
    def needs_equipment_attention(self):
        """Un lot present sans equipement doit etre signale."""
        return self.is_present and self.active_equipment_count == 0
    
    def __repr__(self):
        return f"<Lot {self.name}>"


class LotTask(db.Model):
    """Tâche d'un lot de maintenance."""
    __tablename__ = "lot_tasks"
    
    id = db.Column(db.Integer, primary_key=True)
    lot_id = db.Column(db.Integer, db.ForeignKey("lots.id"), nullable=False)
    num_tache = db.Column(db.String(10), nullable=True)
    tache = db.Column(db.Text, nullable=True)
    periodicite = db.Column(db.String(200), nullable=True)
    contrat = db.Column(db.Boolean, default=False)
    company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True)
    contract_id = db.Column(db.Integer, db.ForeignKey("contracts.id"), nullable=True)
    gestionnaire = db.Column(db.String(50), nullable=True)
    jours_entre_interventions = db.Column(db.Integer, nullable=True)
    type_maintenance = db.Column(db.String(50), nullable=True)
    duree_minutes = db.Column(db.Integer, nullable=True)  # Durée estimée en minutes
    trigger_type = db.Column(db.String(20), nullable=False, default="calendar")
    trigger_event = db.Column(db.String(80), nullable=True)
    meter_threshold = db.Column(db.Float, nullable=True)
    season_start_month = db.Column(db.Integer, nullable=True)
    season_end_month = db.Column(db.Integer, nullable=True)
    advance_days = db.Column(db.Integer, nullable=False, default=0)
    is_active = db.Column(db.Boolean, nullable=False, default=True)
    application_scope = db.Column(db.String(20), nullable=False, default="auto")
    # V2.1b: la durée est une valeur métier par élément (ou par zone pour
    # les espaces verts), jamais une durée implicite du moteur.
    duration_mode = db.Column(db.String(20), nullable=False, default="unit")
    executor_type = db.Column(db.String(30), nullable=False, default="undefined")
    scope_mode = db.Column(db.String(20), nullable=False, default="dynamic")
    unavailable_policy = db.Column(db.String(20), nullable=False, default="suspend")
    after_repair_policy = db.Column(db.String(20), nullable=False, default="preserve")
    is_safety_critical = db.Column(db.Boolean, nullable=False, default=False)
    # Phase 2.1c : nature métier et exécution fractionnable.
    task_nature = db.Column(db.String(30), nullable=False, default="unknown")
    interruptible = db.Column(db.Boolean, nullable=False, default=False)
    splittable = db.Column(db.Boolean, nullable=False, default=False)
    minimum_segment_minutes = db.Column(db.Integer, nullable=True)
    allow_next_day_resume = db.Column(db.Boolean, nullable=False, default=False)
    requires_safe_pause = db.Column(db.Boolean, nullable=False, default=False)
    company = db.relationship("Company")
    contract = db.relationship("Contract")
    equipment_scope = db.relationship(
        "Equipment", secondary="lot_task_equipments",
        back_populates="preventive_tasks", lazy="selectin",
    )

    @property
    def duration_is_configured(self):
        return bool(self.duree_minutes and self.duree_minutes > 0)

    def applicable_equipments(self):
        """Retourne le périmètre effectif sans créer de tournée globale.

        Un périmètre manuel est strictement limité aux équipements choisis;
        le périmètre dynamique suit le lot et inclut les équipements ajoutés.
        """
        from .equipment import Equipment
        if self.scope_mode == "manual":
            return [e for e in self.equipment_scope if not e.is_deleted]
        # Résolution par niveaux : un équipement est rattaché directement au
        # lot ou hérite du lot d'un parent.  On évite ainsi le N+1 de
        # ``effective_lot_id`` (qui chargeait chaque parent en Python).
        result = Equipment.query.filter(
            Equipment.is_deleted.is_(False), Equipment.lot_id == self.lot_id
        ).all()
        frontier = [item.id for item in result]
        while frontier:
            # Les enfants sans lot héritent du lot de leur parent. Les enfants
            # ayant déjà un lot propre sont volontairement exclus de la chaîne.
            inherited = Equipment.query.filter(
                Equipment.is_deleted.is_(False),
                Equipment.parent_id.in_(frontier),
                Equipment.lot_id.is_(None),
            ).all()
            result.extend(inherited)
            frontier = [item.id for item in inherited]
        return result

    def duration_for_equipment(self, equipment):
        """Durée calculée pour une cible, en tenant compte de sa quantité."""
        if not self.duration_is_configured:
            return 0
        if self.duration_mode == "zone":
            room = getattr(equipment, "room", None)
            zone = getattr(room, "zone", None) if room else None
            if not zone:
                return 0
            label = (self.tache or "").lower()
            if "tonte" in label:
                return int(zone.mowing_minutes or 0)
            if "bordure" in label:
                return int(zone.edging_minutes or 0)
            if "haie" in label:
                return int(zone.hedge_minutes or 0)
            if any(word in label for word in ("ramassage", "évacuation", "branches")):
                return int(zone.branch_removal_minutes or 0)
            return 0
        if self.duration_mode != "unit":
            return self.duree_minutes
        quantity = max(int(getattr(equipment, "quantity", 1) or 1), 1)
        return self.duree_minutes * quantity
    
    def effective_duration(self):
        """Duree previsionnelle auto-adaptee pour cette tache de lot.
        
        Si duree_minutes est defini manuellement, on l'utilise.
        Sinon on calcule la moyenne des durees reelles des interventions 
        passees pour ce lot + ce type de tache.
        Aucune valeur arbitraire n'est inventée si la durée n'est pas connue.
        """
        from sqlalchemy import func
        if self.duree_minutes:
            return self.duree_minutes
        # Moyenne des interventions de ce lot
        avg = db.session.query(func.avg(Intervention.actual_duration)).filter(
            Intervention.lot_id == self.lot_id,
            Intervention.actual_duration.isnot(None)
        ).scalar()
        if avg and avg > 0:
            return int(round(avg))
        return 0
    
    def __repr__(self):
        return f"<LotTask {self.num_tache or self.id}>"


class WorkRequest(db.Model):
    """Demande de travaux suivie en interne par le technicien."""
    __tablename__ = "work_requests"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), nullable=False)
    description = db.Column(db.Text, nullable=False)
    status = db.Column(db.String(40), nullable=False, default="brouillon", index=True)
    execution_mode = db.Column(db.String(30), nullable=False, default="interne")
    priority = db.Column(db.String(20), nullable=False, default="normale")
    equipment_id = db.Column(db.Integer, db.ForeignKey("equipments.id"), nullable=True)
    service_id = db.Column(db.Integer, db.ForeignKey("services.id"), nullable=True)
    company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True)
    created_by_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    chief_decision = db.Column(db.String(20), nullable=True)
    department_decision = db.Column(db.String(20), nullable=True)
    chief_decision_date = db.Column(db.Date, nullable=True)
    department_decision_date = db.Column(db.Date, nullable=True)
    planned_date = db.Column(db.Date, nullable=True)
    completed_date = db.Column(db.Date, nullable=True)
    actual_minutes = db.Column(db.Integer, nullable=True)
    parts_cost = db.Column(db.Numeric(10, 2), nullable=True)
    notes = db.Column(db.Text, nullable=True)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    equipment = db.relationship("Equipment")
    service = db.relationship("Service")
    company = db.relationship("Company")
    created_by = db.relationship("User")
    quotes = db.relationship("WorkRequestQuote", back_populates="request", cascade="all, delete-orphan")
    events = db.relationship("WorkRequestEvent", back_populates="request", cascade="all, delete-orphan", order_by="WorkRequestEvent.created_at")


class WorkRequestQuote(db.Model):
    __tablename__ = "work_request_quotes"
    id = db.Column(db.Integer, primary_key=True)
    request_id = db.Column(db.Integer, db.ForeignKey("work_requests.id", ondelete="CASCADE"), nullable=False)
    company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True)
    reference = db.Column(db.String(100), nullable=True)
    amount_ht = db.Column(db.Numeric(10, 2), nullable=True)
    amount_ttc = db.Column(db.Numeric(10, 2), nullable=True)
    quote_date = db.Column(db.Date, nullable=True)
    valid_until = db.Column(db.Date, nullable=True)
    status = db.Column(db.String(20), nullable=False, default="en_attente")
    file_path = db.Column(db.String(500), nullable=True)
    notes = db.Column(db.Text, nullable=True)
    request = db.relationship("WorkRequest", back_populates="quotes")
    company = db.relationship("Company")


class WorkRequestEvent(db.Model):
    __tablename__ = "work_request_events"
    id = db.Column(db.Integer, primary_key=True)
    request_id = db.Column(db.Integer, db.ForeignKey("work_requests.id", ondelete="CASCADE"), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    old_status = db.Column(db.String(40), nullable=True)
    new_status = db.Column(db.String(40), nullable=False)
    comment = db.Column(db.Text, nullable=True)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    request = db.relationship("WorkRequest", back_populates="events")
    user = db.relationship("User")


class LotService(db.Model):
    """Association entre lots et services."""
    __tablename__ = "lot_services"
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    lot_id = db.Column(db.Integer, db.ForeignKey("lots.id"), nullable=False)
    service_id = db.Column(db.Integer, db.ForeignKey("services.id"), nullable=False)
    assigned_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    def __repr__(self):
        return f"<LotService {self.lot_id} - {self.service_id}>"


class WatchdogLog(db.Model):
    """Log centralise des evenements des watchdogs."""
    __tablename__ = "watchdog_logs"
    
    id = db.Column(db.Integer, primary_key=True)
    watchdog_name = db.Column(db.String(50), nullable=False, index=True)
    level = db.Column(db.String(20), nullable=False, default='info')  # debug, info, warning, error
    message = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), index=True)
    
    def __repr__(self):
        return f"<WatchdogLog {self.watchdog_name} {self.level}>"
