<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Core\Auth;
use App\Core\Database;
use App\Core\Notifier;
use App\Models\Settings;
use PDO;

class QuotesController extends Controller
{
    private function ensureQuoteTables(\PDO $pdo): void
    {
        // Crée les tables devis si absentes (schéma minimal compatible)
        $pdo->exec("CREATE TABLE IF NOT EXISTS quotes (
            id INT AUTO_INCREMENT PRIMARY KEY,
            quote_no VARCHAR(64) NOT NULL,
            client_name VARCHAR(255) NOT NULL,
            related_type VARCHAR(64) NULL,
            related_ref VARCHAR(128) NULL,
            quote_date DATE NOT NULL,
            status VARCHAR(64) NOT NULL DEFAULT 'En attente',
            total_ht DECIMAL(12,2) NOT NULL DEFAULT 0,
            total_tva DECIMAL(12,2) NOT NULL DEFAULT 0,
            total_ttc DECIMAL(12,2) NOT NULL DEFAULT 0,
            currency VARCHAR(8) NOT NULL DEFAULT 'XOF',
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
        $pdo->exec("CREATE TABLE IF NOT EXISTS quote_items (
            id INT AUTO_INCREMENT PRIMARY KEY,
            quote_id INT NOT NULL,
            designation VARCHAR(255) NOT NULL,
            unit VARCHAR(16) NOT NULL DEFAULT 'u',
            quantity DECIMAL(12,2) NOT NULL DEFAULT 0,
            unit_price DECIMAL(12,2) NOT NULL DEFAULT 0,
            total_line DECIMAL(12,2) NOT NULL DEFAULT 0,
            FOREIGN KEY (quote_id) REFERENCES quotes(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");

        // Colonnes additionnelles (motif de rejet, date changement statut)
        try {
            $col = $pdo->prepare("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'quotes' AND COLUMN_NAME = 'reject_reason'");
            $col->execute();
            if ((int)$col->fetchColumn() === 0) {
                $pdo->exec("ALTER TABLE quotes ADD COLUMN reject_reason TEXT NULL");
            }
        } catch (\Throwable $e) { /* ignore */ }
        try {
            $col2 = $pdo->prepare("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'quotes' AND COLUMN_NAME = 'status_changed_at'");
            $col2->execute();
            if ((int)$col2->fetchColumn() === 0) {
                $pdo->exec("ALTER TABLE quotes ADD COLUMN status_changed_at DATETIME NULL AFTER updated_at");
            }
        } catch (\Throwable $e) { /* ignore */ }

        // Historique des mouvements de status
        try {
            $pdo->exec("CREATE TABLE IF NOT EXISTS quote_history (
                id INT AUTO_INCREMENT PRIMARY KEY,
                quote_id INT NOT NULL,
                changed_by INT NULL,
                from_status VARCHAR(64) NULL,
                to_status VARCHAR(64) NOT NULL,
                reason TEXT NULL,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (quote_id) REFERENCES quotes(id) ON DELETE CASCADE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
        } catch (\Throwable $e) { /* ignore */ }
    }

    public function index(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        $pdo = Database::pdo();
        // Tolérance: créer tables si absentes et éviter 500
        $this->ensureQuoteTables($pdo);
        // Filtre statut optionnel
        $filterStatus = trim($_GET['status'] ?? '');
        try {
            if ($filterStatus !== '') {
                $st = $pdo->prepare('SELECT * FROM quotes WHERE status = ? ORDER BY id DESC');
                $st->execute([$filterStatus]);
                $quotes = $st->fetchAll();
            } else {
                $quotes = $pdo->query('SELECT * FROM quotes ORDER BY id DESC')->fetchAll();
            }
        } catch (\Throwable $e) { $quotes = []; }

        // Stats globales
        $stats = [ 'total' => 0, 'sum_ht' => 0.0, 'sum_tva' => 0.0, 'sum_ttc' => 0.0, 'last30_count' => 0, 'last30_ttc' => 0.0 ];
        try { $stats['total'] = (int)$pdo->query('SELECT COUNT(*) FROM quotes')->fetchColumn(); } catch (\Throwable $e) {}
        try {
            $row = $pdo->query('SELECT COALESCE(SUM(total_ht),0) AS ht, COALESCE(SUM(total_tva),0) AS tva, COALESCE(SUM(total_ttc),0) AS ttc FROM quotes')->fetch();
            if ($row) { $stats['sum_ht'] = (float)$row['ht']; $stats['sum_tva'] = (float)$row['tva']; $stats['sum_ttc'] = (float)$row['ttc']; }
        } catch (\Throwable $e) {}
        try {
            $row = $pdo->query("SELECT COUNT(*) AS c, COALESCE(SUM(total_ttc),0) AS ttc FROM quotes WHERE quote_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)")->fetch();
            if ($row) { $stats['last30_count'] = (int)$row['c']; $stats['last30_ttc'] = (float)$row['ttc']; }
        } catch (\Throwable $e) {}

        // Stats par statut
        $statusStats = [];
        try {
            $statusStats = $pdo->query('SELECT status, COUNT(*) AS c, COALESCE(SUM(total_ttc),0) AS ttc FROM quotes GROUP BY status ORDER BY status')->fetchAll();
        } catch (\Throwable $e) { $statusStats = []; }

        // Stats mensuelles (6 derniers mois)
        $monthlyStats = [];
        try {
            $monthlyStats = $pdo->query("SELECT DATE_FORMAT(quote_date, '%Y-%m') AS ym, COUNT(*) AS c, COALESCE(SUM(total_ttc),0) AS ttc FROM quotes GROUP BY ym ORDER BY ym DESC LIMIT 6")->fetchAll();
        } catch (\Throwable $e) { $monthlyStats = []; }

        $this->view('quotes/index', compact('quotes','stats','statusStats','monthlyStats','filterStatus'));
    }

    public function create(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        $pdo = Database::pdo();
        // Créer tables devis si absentes
        $this->ensureQuoteTables($pdo);
        // Tolérer absence de tables coûts
        try {
            $items = $pdo->query('SELECT i.*, c.name as category_name FROM cost_items i JOIN cost_categories c ON c.id=i.category_id ORDER BY c.name, i.designation')->fetchAll();
        } catch (\Throwable $e) { $items = []; }
        try {
            $categories = $pdo->query('SELECT id, name FROM cost_categories ORDER BY name')->fetchAll();
        } catch (\Throwable $e) { $categories = []; }
        $clients = $pdo->query('SELECT id, name FROM clients WHERE active = 1 ORDER BY name')->fetchAll();
        $currency = Settings::get('default_currency', 'XOF');
        $vat = (float)Settings::get('vat_rate', '18');
    $isModal = isset($_GET['modal']) && $_GET['modal'] == '1';
    $data = compact('items','categories','clients','currency','vat');
        if ($isModal) { $data['_layout'] = 'none'; }
        $this->view('quotes/create', $data);
    }

    public function store(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $this->redirect('/quotes'); }

        $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';

        // Client via liste déroulante (id) → nom, fallback éventuel
        $clientId = (int)($_POST['client_id'] ?? 0);
        $client = trim($_POST['client_name'] ?? '');
        if ($clientId > 0) {
            $stmtC = Database::pdo()->prepare('SELECT name FROM clients WHERE id = ?');
            $stmtC->execute([$clientId]);
            $name = $stmtC->fetchColumn();
            if ($name) { $client = $name; }
        }
        $date = $_POST['quote_date'] ?? date('Y-m-d');
        $currency = $_POST['currency'] ?? 'XOF';
        $status = $_POST['status'] ?? 'En attente';
        $related_type = $_POST['related_type'] ?? '';
        $related_ref = $_POST['related_ref'] ?? null;

        $lines = $_POST['lines'] ?? [];
        $vat = (float)($_POST['vat_rate'] ?? (Settings::get('vat_rate', '18')));

        $total_ht = 0.0;
        foreach ($lines as $ln) {
            $q = (float)($ln['quantity'] ?? 0);
            $p = (float)($ln['unit_price'] ?? 0);
            $total_ht += $q * $p;
        }
        $total_tva = $total_ht * ($vat / 100.0);
        $total_ttc = $total_ht + $total_tva;

        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        $pdo->beginTransaction();
        try {
            $no = $this->generateQuoteNo();
            $stmt = $pdo->prepare('INSERT INTO quotes(quote_no,client_name,related_type,related_ref,quote_date,status,total_ht,total_tva,total_ttc,currency) VALUES(?,?,?,?,?,?,?,?,?,?)');
            $stmt->execute([$no,$client,$related_type,$related_ref,$date,$status,$total_ht,$total_tva,$total_ttc,$currency]);
            $quoteId = (int)$pdo->lastInsertId();

            $stmtItem = $pdo->prepare('INSERT INTO quote_items(quote_id,designation,unit,quantity,unit_price,total_line) VALUES(?,?,?,?,?,?)');
            foreach ($lines as $ln) {
                $designation = trim($ln['designation'] ?? '');
                if ($designation === '') continue;
                $unit = trim($ln['unit'] ?? 'u');
                $q = (float)($ln['quantity'] ?? 0);
                $p = (float)($ln['unit_price'] ?? 0);
                $total_line = $q * $p;
                $stmtItem->execute([$quoteId,$designation,$unit,$q,$p,$total_line]);
            }
            // Historiser la création (to_status = statut initial)
            try {
                $this->ensureQuoteTables($pdo);
                $u = \App\Core\Auth::user();
                $uid = (int)($u['id'] ?? 0);
                $h = $pdo->prepare('INSERT INTO quote_history(quote_id, changed_by, from_status, to_status, reason) VALUES (?,?,?,?,?)');
                $h->execute([$quoteId, $uid ?: null, null, $status, null]);
            } catch (\Throwable $e) { /* ignore hist create */ }

            $pdo->commit();
        } catch (\Throwable $e) {
            $pdo->rollBack();
            if ($isAjax) {
                http_response_code(500);
                header('Content-Type: application/json');
                echo json_encode(['ok' => false, 'error' => $e->getMessage()]);
                return;
            } else {
                http_response_code(500);
                echo 'Erreur devis: ' . htmlspecialchars($e->getMessage());
                return;
            }
        }
        if ($isAjax) {
            header('Content-Type: application/json');
            echo json_encode(['ok' => true]);
            return;
        } else {
            $this->redirect('/quotes');
        }
    }

    private function generateQuoteNo(): string
    {
        $d = new \DateTime();
        return 'DEV-' . $d->format('ymd-His') . '-' . random_int(100,999);
    }

    public function clientHints(): void
    {
        if (!Auth::check()) { http_response_code(401); echo 'Unauthorized'; return; }
        Auth::requireRole(['admin','agent']);
        header('Content-Type: application/json');
        $clientId = (int)($_GET['client_id'] ?? 0);
        if ($clientId <= 0) { echo json_encode(['related_type' => '', 'related_ref' => '']); return; }
        $pdo = Database::pdo();
        // Récupérer le dernier incident du client pour proposer type=incident et référence = ticket
        $stmt = $pdo->prepare('SELECT ticket_id FROM incidents WHERE client_id = ? ORDER BY declared_at DESC LIMIT 1');
        $stmt->execute([$clientId]);
        $ticket = $stmt->fetchColumn();
        if ($ticket) {
            echo json_encode(['related_type' => 'incident', 'related_ref' => $ticket]);
        } else {
            echo json_encode(['related_type' => '', 'related_ref' => '']);
        }
    }

    public function show(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        
        $id = (int)($_GET['id'] ?? 0);
        if (!$id) {
            echo '<div class="alert alert-danger">ID manquant</div>';
            return;
        }
        
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        
        try {
            // Récupérer le devis
            $stmt = $pdo->prepare('SELECT * FROM quotes WHERE id = ?');
            $stmt->execute([$id]);
            $quote = $stmt->fetch();
            
            if (!$quote) {
                echo '<div class="alert alert-danger">Devis introuvable</div>';
                return;
            }
            
            // Récupérer les lignes
            $stmt = $pdo->prepare('SELECT * FROM quote_items WHERE quote_id = ?');
            $stmt->execute([$id]);
            $items = $stmt->fetchAll();

            // Historique
            try {
                $h = $pdo->prepare('SELECT h.*, u.name AS user_name, u.email AS user_email FROM quote_history h LEFT JOIN users u ON u.id = h.changed_by WHERE h.quote_id = ? ORDER BY h.created_at DESC, h.id DESC');
                $h->execute([$id]);
                $history = $h->fetchAll() ?: [];
            } catch (\Throwable $e) { $history = []; }
            
            $isModal = isset($_GET['modal']) && $_GET['modal'] == '1';
            $data = compact('quote', 'items', 'history');
            if ($isModal) { $data['_layout'] = 'none'; }

            $this->view('quotes/show', $data);
        } catch (\Throwable $e) {
            echo '<div class="alert alert-danger">Erreur: ' . htmlspecialchars($e->getMessage()) . '</div>';
        }
    }

    public function edit(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        
        $id = (int)($_GET['id'] ?? 0);
        if (!$id) {
            echo '<div class="alert alert-danger">ID manquant</div>';
            return;
        }
        
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        
        try {
            // Récupérer le devis
            $stmt = $pdo->prepare('SELECT * FROM quotes WHERE id = ?');
            $stmt->execute([$id]);
            $quote = $stmt->fetch();
            
            if (!$quote) {
                echo '<div class="alert alert-danger">Devis introuvable</div>';
                return;
            }
            
            // Récupérer les lignes
            $stmt = $pdo->prepare('SELECT * FROM quote_items WHERE quote_id = ?');
            $stmt->execute([$id]);
            $quoteItems = $stmt->fetchAll();
            
            // Récupérer les données pour le formulaire
            try {
                $items = $pdo->query('SELECT i.*, c.name as category_name FROM cost_items i JOIN cost_categories c ON c.id=i.category_id ORDER BY c.name, i.designation')->fetchAll();
            } catch (\Throwable $e) { $items = []; }
            
            try {
                $categories = $pdo->query('SELECT id, name FROM cost_categories ORDER BY name')->fetchAll();
            } catch (\Throwable $e) { $categories = []; }
            
            $clients = $pdo->query('SELECT id, name FROM clients WHERE active = 1 ORDER BY name')->fetchAll();
            
            $isModal = isset($_GET['modal']) && $_GET['modal'] == '1';
            $data = compact('quote', 'quoteItems', 'items', 'categories', 'clients');
            if ($isModal) { $data['_layout'] = 'none'; }
            
            $this->view('quotes/edit', $data);
        } catch (\Throwable $e) {
            echo '<div class="alert alert-danger">Erreur: ' . htmlspecialchars($e->getMessage()) . '</div>';
        }
    }

    public function update(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $this->redirect('/quotes'); }

        $id = (int)($_POST['id'] ?? $_GET['id'] ?? 0);
        if (!$id) {
            http_response_code(400);
            echo json_encode(['ok' => false, 'error' => 'ID manquant']);
            return;
        }

        $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';

        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        
        try {
            // Vérifier que le devis existe
            $stmt = $pdo->prepare('SELECT * FROM quotes WHERE id = ?');
            $stmt->execute([$id]);
            $existing = $stmt->fetch();
            if (!$existing) {
                throw new \Exception('Devis introuvable');
            }
            $old_ht  = (float)($existing['total_ht'] ?? 0);
            $old_tva = (float)($existing['total_tva'] ?? 0);
            $old_ttc = (float)($existing['total_ttc'] ?? 0);
            $old_status = trim((string)($existing['status'] ?? ''));
            $cntStmt = $pdo->prepare('SELECT COUNT(*) FROM quote_items WHERE quote_id = ?');
            $cntStmt->execute([$id]);
            $old_items = (int)$cntStmt->fetchColumn();
            
            // Récupérer les données
            $clientId = (int)($_POST['client_id'] ?? 0);
            $client = trim($_POST['client_name'] ?? '');
            if ($clientId > 0) {
                $stmtC = $pdo->prepare('SELECT name FROM clients WHERE id = ?');
                $stmtC->execute([$clientId]);
                $name = $stmtC->fetchColumn();
                if ($name) { $client = $name; }
            }
            
            $date = $_POST['quote_date'] ?? date('Y-m-d');
            $currency = $_POST['currency'] ?? 'XOF';
            $status = $_POST['status'] ?? 'En attente';
            $related_type = $_POST['related_type'] ?? '';
            $related_ref = $_POST['related_ref'] ?? null;
            
            $lines = $_POST['lines'] ?? [];
            $vat = (float)($_POST['vat_rate'] ?? 18);
            
            $total_ht = 0.0;
            foreach ($lines as $ln) {
                $q = (float)($ln['quantity'] ?? 0);
                $p = (float)($ln['unit_price'] ?? 0);
                $total_ht += $q * $p;
            }
            $total_tva = $total_ht * ($vat / 100.0);
            $total_ttc = $total_ht + $total_tva;
            
            $pdo->beginTransaction();
            
            // Mettre à jour le devis
            $stmt = $pdo->prepare('UPDATE quotes SET client_name=?, related_type=?, related_ref=?, quote_date=?, status=?, total_ht=?, total_tva=?, total_ttc=?, currency=?, updated_at=NOW() WHERE id=?');
            $stmt->execute([$client, $related_type, $related_ref, $date, $status, $total_ht, $total_tva, $total_ttc, $currency, $id]);
            
            // Supprimer les anciennes lignes
            $stmt = $pdo->prepare('DELETE FROM quote_items WHERE quote_id = ?');
            $stmt->execute([$id]);
            
            // Insérer les nouvelles lignes
            $stmtItem = $pdo->prepare('INSERT INTO quote_items(quote_id,designation,unit,quantity,unit_price,total_line) VALUES(?,?,?,?,?,?)');
            foreach ($lines as $ln) {
                $designation = trim($ln['designation'] ?? '');
                if ($designation === '') continue;
                $unit = trim($ln['unit'] ?? 'u');
                $q = (float)($ln['quantity'] ?? 0);
                $p = (float)($ln['unit_price'] ?? 0);
                $total_line = $q * $p;
                $stmtItem->execute([$id, $designation, $unit, $q, $p, $total_line]);
            }
            
            $pdo->commit();

            // Historiser la mise à jour (diff totaux et nombre de lignes)
            try {
                $this->ensureQuoteTables($pdo);
                $u = \App\Core\Auth::user();
                $uid = (int)($u['id'] ?? 0);
                $reason = 'Mise à jour du devis: HT ' . number_format($old_ht,2,',',' ') . ' → ' . number_format($total_ht,2,',',' ') . ', TVA ' . number_format($old_tva,2,',',' ') . ' → ' . number_format($total_tva,2,',',' ') . ', TTC ' . number_format($old_ttc,2,',',' ') . ' → ' . number_format($total_ttc,2,',',' ');
                $newCntStmt = $pdo->prepare('SELECT COUNT(*) FROM quote_items WHERE quote_id = ?');
                $newCntStmt->execute([$id]);
                $new_items = (int)$newCntStmt->fetchColumn();
                if ($old_items !== $new_items) {
                    $reason .= '; Lignes ' . $old_items . ' → ' . $new_items;
                }
                $h = $pdo->prepare('INSERT INTO quote_history(quote_id, changed_by, from_status, to_status, reason) VALUES (?,?,?,?,?)');
                $h->execute([$id, $uid ?: null, $old_status ?: null, 'Mise à jour', $reason]);
            } catch (\Throwable $e) { /* ignore hist update */ }
            
            if ($isAjax) {
                header('Content-Type: application/json');
                echo json_encode(['ok' => true]);
                return;
            } else {
                $this->redirect('/quotes');
            }
        } catch (\Throwable $e) {
            $pdo->rollBack();
            if ($isAjax) {
                http_response_code(500);
                header('Content-Type: application/json');
                echo json_encode(['ok' => false, 'error' => $e->getMessage()]);
                return;
            } else {
                http_response_code(500);
                echo 'Erreur: ' . htmlspecialchars($e->getMessage());
                return;
            }
        }
    }

    public function destroy(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        
        $id = (int)($_POST['id'] ?? $_GET['id'] ?? 0);
        if (!$id) {
            http_response_code(400);
            echo json_encode(['ok' => false, 'error' => 'ID manquant']);
            return;
        }
        
        $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
        
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        
        try {
            $pdo->beginTransaction();
            
            // Supprimer les lignes
            $stmt = $pdo->prepare('DELETE FROM quote_items WHERE quote_id = ?');
            $stmt->execute([$id]);
            
            // Supprimer le devis
            $stmt = $pdo->prepare('DELETE FROM quotes WHERE id = ?');
            $stmt->execute([$id]);
            
            $pdo->commit();
            
            if ($isAjax) {
                header('Content-Type: application/json');
                echo json_encode(['ok' => true]);
                return;
            } else {
                $this->redirect('/quotes');
            }
        } catch (\Throwable $e) {
            $pdo->rollBack();
            if ($isAjax) {
                http_response_code(500);
                header('Content-Type: application/json');
                echo json_encode(['ok' => false, 'error' => $e->getMessage()]);
                return;
            } else {
                http_response_code(500);
                echo 'Erreur: ' . htmlspecialchars($e->getMessage());
                return;
            }
        }
    }

    public function duplicate(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        $isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
        $id = (int)($_POST['id'] ?? 0);
        if ($id <= 0) { http_response_code(400); echo json_encode(['ok'=>false,'error'=>'ID manquant']); return; }
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        try {
            $pdo->beginTransaction();
            $q = $pdo->prepare('SELECT * FROM quotes WHERE id=?');
            $q->execute([$id]);
            $quote = $q->fetch();
            if (!$quote) throw new \Exception('Devis introuvable');
            $newNo = $this->generateQuoteNo();
            $stmt = $pdo->prepare('INSERT INTO quotes(quote_no,client_name,related_type,related_ref,quote_date,status,total_ht,total_tva,total_ttc,currency) VALUES(?,?,?,?,?,?,?,?,?,?)');
            $stmt->execute([$newNo,$quote['client_name'],$quote['related_type'],$quote['related_ref'],date('Y-m-d'),$quote['status'],$quote['total_ht'],$quote['total_tva'],$quote['total_ttc'],$quote['currency']]);
            $newId = (int)$pdo->lastInsertId();
            $it = $pdo->prepare('SELECT * FROM quote_items WHERE quote_id=?');
            $it->execute([$id]);
            $items = $it->fetchAll();
            $ins = $pdo->prepare('INSERT INTO quote_items(quote_id,designation,unit,quantity,unit_price,total_line) VALUES(?,?,?,?,?,?)');
            foreach ($items as $ln) {
                $ins->execute([$newId,$ln['designation'],$ln['unit'],$ln['quantity'],$ln['unit_price'],$ln['total_line']]);
            }
            $pdo->commit();

            // Historiser duplication (nouveau et ancien devis)
            try {
                $this->ensureQuoteTables($pdo);
                $u = \App\Core\Auth::user();
                $uid = (int)($u['id'] ?? 0);
                $h = $pdo->prepare('INSERT INTO quote_history(quote_id, changed_by, from_status, to_status, reason) VALUES (?,?,?,?,?)');
                $h->execute([$newId, $uid ?: null, null, 'Duplication', 'Dupliqué depuis #'.(int)$id.' ('.$quote['quote_no'].')']);
                $h->execute([$id, $uid ?: null, null, 'Duplication', 'Dupliqué vers #'.(int)$newId.' ('.$newNo.')']);
            } catch (\Throwable $e) { /* ignore hist duplicate */ }
            header('Content-Type: application/json'); echo json_encode(['ok'=>true,'id'=>$newId]);
        } catch (\Throwable $e) {
            $pdo->rollBack(); http_response_code(500); header('Content-Type: application/json'); echo json_encode(['ok'=>false,'error'=>$e->getMessage()]);
        }
    }

    public function pdf(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        $id = (int)($_GET['id'] ?? 0);
        if ($id <= 0) { http_response_code(400); echo 'ID manquant'; return; }
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        $q = $pdo->prepare('SELECT * FROM quotes WHERE id=?');
        $q->execute([$id]);
        $quote = $q->fetch();
        if (!$quote) { http_response_code(404); echo 'Devis introuvable'; return; }
        $it = $pdo->prepare('SELECT * FROM quote_items WHERE quote_id=?');
        $it->execute([$id]);
        $items = $it->fetchAll();
        $includeHistory = isset($_GET['history']) || isset($_GET['with_history']);
        $html = '<html><head><meta charset="utf-8"><style>body{font-family:DejaVu Sans, Arial; font-size:12px;} table{width:100%; border-collapse:collapse;} th,td{border:1px solid #ccc; padding:6px;} th{background:#f5f5f5;} h1{font-size:18px;} .right{text-align:right} .muted{color:#666; font-size:11px}</style></head><body>';
        $html .= '<h1>Devis '.htmlspecialchars($quote['quote_no']).'</h1>';
        $html .= '<p><strong>Client:</strong> '.htmlspecialchars($quote['client_name']).'<br><strong>Date:</strong> '.htmlspecialchars($quote['quote_date']).'<br><strong>Statut:</strong> '.htmlspecialchars($quote['status']).'</p>';
        $html .= '<table><thead><tr><th>Désignation</th><th>Unité</th><th>Qté</th><th>PU</th><th>Total</th></tr></thead><tbody>';
        foreach ($items as $ln) {
            $html .= '<tr><td>'.htmlspecialchars($ln['designation']).'</td><td>'.htmlspecialchars($ln['unit']).'</td><td class="right">'.number_format((float)$ln['quantity'],3,',',' ').'</td><td class="right">'.number_format((float)$ln['unit_price'],2,',',' ').'</td><td class="right">'.number_format((float)$ln['total_line'],2,',',' ').'</td></tr>';
        }
        $html .= '</tbody></table>';
        $html .= '<p class="right"><strong>Total HT:</strong> '.number_format((float)$quote['total_ht'],2,',',' ').' '.$quote['currency'].'<br><strong>TVA:</strong> '.number_format((float)$quote['total_tva'],2,',',' ').' '.$quote['currency'].'<br><strong>Total TTC:</strong> '.number_format((float)$quote['total_ttc'],2,',',' ').' '.$quote['currency'].'</p>';
        if ($includeHistory) {
            try {
                $h = $pdo->prepare('SELECT h.*, u.name AS user_name, u.email AS user_email FROM quote_history h LEFT JOIN users u ON u.id = h.changed_by WHERE h.quote_id = ? ORDER BY h.created_at DESC, h.id DESC');
                $h->execute([$id]);
                $histories = $h->fetchAll() ?: [];
                if (!empty($histories)) {
                    $html .= '<h2 style="font-size:16px; margin-top:20px;">Historique des mouvements</h2>';
                    $html .= '<table><thead><tr><th style="width:150px">Date</th><th style="width:200px">Par</th><th>Action / Statut</th></tr></thead><tbody>';
                    foreach ($histories as $row) {
                        $by = !empty($row['user_name']) ? $row['user_name'] : (!empty($row['user_email']) ? $row['user_email'] : 'Système');
                        $date = !empty($row['created_at']) ? date('d/m/Y H:i', strtotime($row['created_at'])) : '';
                        $action = '';
                        if (!empty($row['from_status'])) { $action .= htmlspecialchars($row['from_status']).' → '; }
                        $action .= htmlspecialchars($row['to_status'] ?? '');
                        if (!empty($row['reason'])) { $action .= '<br><span class="muted">'.nl2br(htmlentities($row['reason'])).'</span>'; }
                        $html .= '<tr><td>'.$date.'</td><td>'.htmlspecialchars($by).'</td><td>'.$action.'</td></tr>';
                    }
                    $html .= '</tbody></table>';
                }
            } catch (\Throwable $e) { /* ignore hist in pdf */ }
        }
        $html .= '</body></html>';
        try {
            $dompdf = new \Dompdf\Dompdf([ 'isRemoteEnabled' => true ]);
            $dompdf->loadHtml($html, 'UTF-8');
            $dompdf->setPaper('A4','portrait');
            $dompdf->render();
            header('Content-Type: application/pdf');
            $dompdf->stream('devis-'.$quote['quote_no'].'.pdf', ['Attachment'=>false]);
        } catch (\Throwable $e) {
            http_response_code(500); echo 'PDF error: '.htmlspecialchars($e->getMessage());
        }
    }

    public function send(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        // Stub: on valide et renvoie ok
        header('Content-Type: application/json'); echo json_encode(['ok'=>true]);
    }

    public function status(): void
    {
        if (!Auth::check()) { $this->redirect('/login'); }
        Auth::requireRole(['admin','agent']);
        $id = (int)($_POST['id'] ?? 0);
        $status = trim($_POST['status'] ?? '');
        $reason = isset($_POST['reason']) ? trim((string)$_POST['reason']) : '';
        if ($id<=0 || $status==='') { http_response_code(400); header('Content-Type: application/json'); echo json_encode(['ok'=>false,'error'=>'Paramètres invalides']); return; }
        $pdo = Database::pdo();
        $this->ensureQuoteTables($pdo);
        try {
            // Charger info devis pour notifications + ancien statut
            $q = $pdo->prepare('SELECT id, quote_no, client_name, total_ttc, currency, status AS old_status FROM quotes WHERE id=?');
            $q->execute([$id]);
            $quote = $q->fetch();

            if ($status === 'Rejeté') {
                if ($reason === '') {
                    http_response_code(422);
                    header('Content-Type: application/json');
                    echo json_encode(['ok'=>false,'error'=>'Le motif est requis pour un rejet.']);
                    return;
                }
                $stmt = $pdo->prepare('UPDATE quotes SET status=?, reject_reason=?, status_changed_at=NOW(), updated_at=NOW() WHERE id=?');
                $ok = $stmt->execute([$status, $reason, $id]);
            } else {
                $stmt = $pdo->prepare('UPDATE quotes SET status=?, reject_reason=NULL, status_changed_at=NOW(), updated_at=NOW() WHERE id=?');
                $ok = $stmt->execute([$status, $id]);
            }

            // Historiser le changement de statut
            try {
                $u = \App\Core\Auth::user();
                $uid = (int)($u['id'] ?? 0);
                $h = $pdo->prepare('INSERT INTO quote_history(quote_id, changed_by, from_status, to_status, reason) VALUES (?,?,?,?,?)');
                $h->execute([$id, $uid ?: null, ($quote['old_status'] ?? null), $status, ($status === 'Rejeté' ? $reason : null)]);
            } catch (\Throwable $e) { /* ignore hist */ }

            // Notifications si "En attente"
            if ($ok && $status === 'En attente') {
                try {
                    $ids = [];
                    $u = $pdo->query("SELECT id FROM users WHERE active=1 AND role_key IN ('admin','manager','superviseur','supervisor')");
                    foreach ($u->fetchAll() as $row) { $ids[] = (int)$row['id']; }
                    if (!empty($ids)) {
                        $title = 'Devis en attente de validation';
                        $qno = $quote['quote_no'] ?? ('DEV-' . (int)$id);
                        $body = 'Le devis <strong>'.htmlentities($qno).'</strong> pour <em>'.htmlentities($quote['client_name'] ?? '')."</em> est en attente.<br>Montant: <strong>".number_format((float)($quote['total_ttc'] ?? 0), 2, ',', ' ').' '.htmlentities($quote['currency'] ?? 'XOF').'</strong>';
                        $url  = rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/'); if ($url === '/') { $url = ''; }
                        $url .= '/quotes/show?id=' . $id;
                        Notifier::notifyUsers($pdo, $ids, $title, strip_tags($body), $url);
                        Notifier::emailUsers($pdo, $ids, $title, $body . '<br><a href="'.htmlentities($url).'">Ouvrir le devis</a>');
                    }
                } catch (\Throwable $e) { /* ignore notifications errors */ }
            }

            // Notifications si "Validé"
            if ($ok && $status === 'Validé') {
                try {
                    $ids = [];
                    $u = $pdo->query("SELECT id FROM users WHERE active=1 AND role_key IN ('admin','manager','superviseur','supervisor')");
                    foreach ($u->fetchAll() as $row) { $ids[] = (int)$row['id']; }
                    if (!empty($ids)) {
                        $title = 'Devis validé';
                        $qno = $quote['quote_no'] ?? ('DEV-' . (int)$id);
                        $body = 'Le devis <strong>'.htmlentities($qno).'</strong> pour <em>'.htmlentities($quote['client_name'] ?? '')."</em> a été validé.<br>Montant: <strong>".number_format((float)($quote['total_ttc'] ?? 0), 2, ',', ' ').' '.htmlentities($quote['currency'] ?? 'XOF').'</strong>';
                        $url  = rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/'); if ($url === '/') { $url = ''; }
                        $url .= '/quotes/show?id=' . $id;
                        Notifier::notifyUsers($pdo, $ids, $title, strip_tags($body), $url);
                        Notifier::emailUsers($pdo, $ids, $title, $body . '<br><a href="'.htmlentities($url).'">Ouvrir le devis</a>');
                    }
                } catch (\Throwable $e) { /* ignore notifications errors */ }
            }

            header('Content-Type: application/json'); echo json_encode(['ok'=>$ok]);
        } catch (\Throwable $e) {
            http_response_code(500);
            header('Content-Type: application/json');
            echo json_encode(['ok'=>false,'error'=>$e->getMessage()]);
        }
    }
}
