<?php
namespace App\Controllers;

use App\Core\Controller;
use App\Core\Database;
use App\Core\MobileLicenseManager;
use App\Core\Notifier;
use App\Core\Config;
use PDO;

class MobileApiController extends Controller
{
    private const MOBILE_TRIAL_DURATION_DAYS = 14;

    private function normalizeMobileTechnicianType(?string $value): string
    {
        $technicianType = strtolower(trim((string)$value));
        if (in_array($technicianType, ['etude', 'etude_raccordement'], true)) {
            return 'raccordement';
        }

        return $technicianType;
    }

    private function verifyUserPassword(array $user, string $password): bool
    {
        $hash = '';
        if (!empty($user['password'] ?? null)) {
            $hash = (string)$user['password'];
        } elseif (!empty($user['password'] ?? null)) {
            $hash = (string)$user['password'];
        }

        if ($hash === '') { return false; }

        if (str_starts_with($hash, '$2y$') || str_starts_with($hash, '$2a$') || str_starts_with($hash, '$argon2')) {
            return password_verify($password, $hash);
        }

        return hash_equals($hash, $password);
    }

    private function respondJson($data, int $status = 200): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
    }

    private function getBearerToken(): ?string
    {
        $hdr = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '';
        if (!$hdr && function_exists('apache_request_headers')) {
            $apacheHeaders = apache_request_headers();
            $hdr = $apacheHeaders['Authorization'] ?? $apacheHeaders['authorization'] ?? '';
        }
        if (!$hdr) { return null; }
        if (preg_match('/^Bearer\s+(.+)$/i', trim($hdr), $m)) {
            return trim($m[1]);
        }
        return null;
    }

    private function ensureApiTables(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS api_tokens (
            id INT AUTO_INCREMENT PRIMARY KEY,
            user_id INT NOT NULL,
            token_hash CHAR(64) NOT NULL,
            name VARCHAR(60) NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            last_used_at DATETIME NULL,
            expires_at DATETIME NULL,
            revoked_at DATETIME NULL,
            UNIQUE KEY uniq_token_hash (token_hash),
            INDEX(user_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        Notifier::ensureDevicesTable($pdo);
        $this->ensureTrialDevicesTable($pdo);
        MobileLicenseManager::ensureSchema($pdo);
    }

    private function ensureTrialDevicesTable(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS mobile_device_trials (
            id INT AUTO_INCREMENT PRIMARY KEY,
            device_id VARCHAR(191) NOT NULL,
            device_fingerprint VARCHAR(191) NULL,
            platform VARCHAR(30) NULL,
            model VARCHAR(120) NULL,
            first_seen_at DATETIME NOT NULL,
            trial_started_at DATETIME NOT NULL,
            last_seen_at DATETIME NOT NULL,
            UNIQUE KEY uniq_device_id (device_id),
            KEY idx_device_fingerprint (device_fingerprint)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        try {
            $pdo->exec("ALTER TABLE mobile_device_trials ADD COLUMN device_fingerprint VARCHAR(191) NULL AFTER device_id");
        } catch (\Throwable $e) {
        }

        try {
            $pdo->exec("ALTER TABLE mobile_device_trials ADD KEY idx_device_fingerprint (device_fingerprint)");
        } catch (\Throwable $e) {
        }
    }

    private function findUserFromToken(PDO $pdo): ?array
    {
        $token = $this->getBearerToken();
        if (!$token) { return null; }
        $hash = hash('sha256', $token);
        $this->ensureApiTables($pdo);

        $st = $pdo->prepare('SELECT user_id FROM api_tokens WHERE token_hash=? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at > NOW()) LIMIT 1');
        $st->execute([$hash]);
        $uid = (int)($st->fetchColumn() ?: 0);
        if ($uid <= 0) { return null; }

        // touch token usage
        $pdo->prepare('UPDATE api_tokens SET last_used_at = NOW() WHERE token_hash=?')->execute([$hash]);

        $u = $pdo->prepare('SELECT id, name, email, role_key, technician_type, assigned_city FROM users WHERE id=? AND active=1 LIMIT 1');
        $u->execute([$uid]);
        $row = $u->fetch(PDO::FETCH_ASSOC);
        if (is_array($row)) {
            $row['role_key'] = strtolower(trim((string)($row['role_key'] ?? '')));
            $row['technician_type'] = $this->normalizeMobileTechnicianType($row['technician_type'] ?? null);
            $row['assigned_city'] = trim((string)($row['assigned_city'] ?? ''));
        }
        return $row ?: null;
    }

    private function createToken(PDO $pdo, int $userId, string $name = 'mobile', int $days = 90): string
    {
        $raw = bin2hex(random_bytes(32));
        $hash = hash('sha256', $raw);
        $this->ensureApiTables($pdo);
        $expires = (new \DateTime())->add(new \DateInterval('P' . $days . 'D'))->format('Y-m-d H:i:s');
        $ins = $pdo->prepare('INSERT INTO api_tokens (user_id, token_hash, name, created_at, expires_at) VALUES (?,?,?,NOW(),?)');
        $ins->execute([$userId, $hash, $name, $expires]);
        return $raw;
    }

    // ================================================================
    //  CONFIG PUBLIQUE — GET /api/mobile/config (sans auth requise)
    // ================================================================
    public function config(): void
    {
        $pdo = Database::pdo();
        $settings = [];
        try {
            $rows = $pdo->query('SELECT `key`, `value` FROM settings')->fetchAll(PDO::FETCH_ASSOC);
            foreach ($rows as $r) { $settings[$r['key']] = $r['value']; }
        } catch (\Throwable $e) { /* table absente, config vide */ }

        $apiBase      = trim((string)($settings['mobile_api_base']  ?? ''));
        $appName      = trim((string)($settings['app_name']         ?? 'Insuite Technicien'));
        $logoPath     = trim((string)($settings['mobile_logo']      ?? $settings['branding_logo'] ?? ''));
        $splashPath   = trim((string)($settings['mobile_splash']    ?? ''));
        $loginBgPath  = trim((string)($settings['mobile_login_bg']  ?? $settings['branding_login_bg'] ?? ''));
        $iconPath     = trim((string)($settings['mobile_icon']      ?? $settings['branding_favicon'] ?? ''));

        $this->respondJson([
            'ok'     => true,
            'config' => [
                'api_base'     => $apiBase     ?: null,
                'app_name'     => $appName,
                'logo_url'     => $logoPath    ? base_url('storage/uploads/' . $logoPath)    : null,
                'splash_url'   => $splashPath  ? base_url('storage/uploads/' . $splashPath)  : null,
                'login_bg_url' => $loginBgPath ? base_url('storage/uploads/' . $loginBgPath) : null,
                'icon_url'     => $iconPath    ? base_url('storage/uploads/' . $iconPath)    : null,
            ],
        ]);
    }

    public function trialState(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }

        $deviceId = trim((string)($_POST['device_id'] ?? ''));
        $deviceFingerprint = trim((string)($_POST['device_fingerprint'] ?? ''));
        $platform = trim((string)($_POST['platform'] ?? 'android'));
        $model = trim((string)($_POST['model'] ?? ''));

        if ($deviceId === '') {
            $this->respondJson(['ok' => false, 'error' => 'missing_device_id'], 400);
            return;
        }

        $pdo = Database::pdo();
        $this->ensureTrialDevicesTable($pdo);

        $select = $pdo->prepare('SELECT id, device_id, device_fingerprint, trial_started_at FROM mobile_device_trials WHERE device_id = ? LIMIT 1');
        $select->execute([$deviceId]);
        $row = $select->fetch(PDO::FETCH_ASSOC);

        if (!$row && $deviceFingerprint !== '') {
            $selectByFingerprint = $pdo->prepare('SELECT id, device_id, device_fingerprint, trial_started_at FROM mobile_device_trials WHERE device_fingerprint = ? ORDER BY id ASC LIMIT 1');
            $selectByFingerprint->execute([$deviceFingerprint]);
            $row = $selectByFingerprint->fetch(PDO::FETCH_ASSOC);
        }

        if (!$row) {
            $insert = $pdo->prepare('INSERT INTO mobile_device_trials (device_id, device_fingerprint, platform, model, first_seen_at, trial_started_at, last_seen_at) VALUES (?, ?, ?, ?, NOW(), NOW(), NOW())');
            $insert->execute([$deviceId, $deviceFingerprint !== '' ? $deviceFingerprint : null, $platform ?: null, $model ?: null]);
            $select->execute([$deviceId]);
            $row = $select->fetch(PDO::FETCH_ASSOC);
        } else {
            $update = $pdo->prepare('UPDATE mobile_device_trials SET device_id = ?, device_fingerprint = ?, platform = ?, model = ?, last_seen_at = NOW() WHERE id = ?');
            $update->execute([
                $deviceId,
                $deviceFingerprint !== '' ? $deviceFingerprint : ($row['device_fingerprint'] ?? null),
                $platform ?: null,
                $model ?: null,
                (int)$row['id'],
            ]);
        }

        $startedAtRaw = (string)($row['trial_started_at'] ?? 'now');
        $startedAt = new \DateTimeImmutable($startedAtRaw);
        $expiresAt = $startedAt->add(new \DateInterval('P' . self::MOBILE_TRIAL_DURATION_DAYS . 'D'));
        $now = new \DateTimeImmutable('now');

        $this->respondJson([
            'ok' => true,
            'trial' => [
                'device_id' => $deviceId,
                'started_at' => $startedAt->format(DATE_ATOM),
                'started_at_ms' => $startedAt->getTimestamp() * 1000,
                'expires_at' => $expiresAt->format(DATE_ATOM),
                'expires_at_ms' => $expiresAt->getTimestamp() * 1000,
                'expired' => $now >= $expiresAt,
                'duration_days' => self::MOBILE_TRIAL_DURATION_DAYS,
            ],
        ]);
    }

    public function login(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }

        $email = trim($_POST['email'] ?? $_POST['username'] ?? '');
        $password = (string)($_POST['password'] ?? '');
        if ($email === '' || $password === '') {
            $this->respondJson(['ok' => false, 'error' => 'missing_credentials'], 400);
            return;
        }

        $pdo = Database::pdo();
        $st = $pdo->prepare('SELECT * FROM users WHERE email = :id AND active = 1 LIMIT 1');
        $st->execute(['id' => $email]);
        $user = $st->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            $license = MobileLicenseManager::getLicenseByUserId($pdo, (int)$user['id']);
            if (!$license || (int)($license['is_enabled'] ?? 0) !== 1 || empty($license['activated_at'])) {
                $this->respondJson(['ok' => false, 'error' => 'needs_license'], 403);
                return;
            }
        }

        if (!$user || !$this->verifyUserPassword($user, $password)) {
            $this->respondJson(['ok' => false, 'error' => 'invalid_credentials'], 401);
            return;
        }

        // 2FA: pour l’instant, l’API renvoie requires_2fa (à implémenter ensuite)
        if (!empty($user['totp_secret'])) {
            $this->respondJson(['ok' => false, 'error' => 'requires_2fa'], 403);
            return;
        }

        MobileLicenseManager::updateUserLastLogin($pdo, (int)$user['id'], 'mobile');
        $token = $this->createToken($pdo, (int)$user['id'], 'mobile');
        $this->respondJson([
            'ok' => true,
            'token' => $token,
            'user' => [
                'id' => (int)$user['id'],
                'name' => $user['name'] ?? '',
                'email' => $user['email'] ?? '',
                'role_key' => strtolower(trim((string)($user['role_key'] ?? 'user'))),
                'technician_type' => $this->normalizeMobileTechnicianType($user['technician_type'] ?? null),
                'assigned_city' => trim((string)($user['assigned_city'] ?? '')),
            ],
        ]);
    }

    public function activationStatus(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }

        $pdo = Database::pdo();
        $this->ensureApiTables($pdo);

        $deviceId = trim((string)($_POST['device_id'] ?? ''));
        $deviceFingerprint = trim((string)($_POST['device_fingerprint'] ?? ''));
        $match = MobileLicenseManager::findActivationByDevice($pdo, $deviceId, $deviceFingerprint);

        if (!$match) {
            $this->respondJson([
                'ok' => true,
                'activation' => [
                    'activated' => false,
                ],
            ]);
            return;
        }

        $this->respondJson([
            'ok' => true,
            'activation' => [
                'activated' => true,
                'email' => $match['email'] ?? $match['email_snapshot'] ?? '',
                'user_name' => $match['name'] ?? '',
                'activated_at' => $match['activated_at'] ?? null,
            ],
        ]);
    }

    public function activate(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }

        $email = MobileLicenseManager::normalizeEmail($_POST['email'] ?? null);
        $code = trim((string)($_POST['code'] ?? ''));
        if ($email === null || $code === '') {
            $this->respondJson(['ok' => false, 'error' => 'missing_activation_data'], 400);
            return;
        }

        $pdo = Database::pdo();
        $this->ensureApiTables($pdo);

        $stmt = $pdo->prepare('SELECT id, name, email, active FROM users WHERE email = ? LIMIT 1');
        $stmt->execute([$email]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$user || (int)($user['active'] ?? 0) !== 1) {
            $this->respondJson(['ok' => false, 'error' => 'user_not_found'], 404);
            return;
        }

        $device = [
            'device_id' => trim((string)($_POST['device_id'] ?? '')),
            'device_fingerprint' => trim((string)($_POST['device_fingerprint'] ?? '')),
            'platform' => trim((string)($_POST['platform'] ?? '')),
            'model' => trim((string)($_POST['model'] ?? '')),
        ];

        try {
            $license = MobileLicenseManager::activateLicense($pdo, $user, $code, $device, $this->getClientIp());
        } catch (\RuntimeException $e) {
            $error = $e->getMessage();
            $status = match ($error) {
                'license_disabled' => 403,
                'code_expired' => 410,
                'code_invalid' => 422,
                default => 400,
            };
            $this->respondJson(['ok' => false, 'error' => $error], $status);
            return;
        }

        $this->respondJson([
            'ok' => true,
            'activation' => [
                'activated' => true,
                'email' => $email,
                'user_name' => $user['name'] ?? '',
                'activated_at' => $license['activated_at'] ?? date('Y-m-d H:i:s'),
            ],
        ]);
    }

    public function me(): void
    {
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) {
            $this->respondJson(['ok' => false, 'error' => 'unauthorized'], 401);
            return;
        }
        $this->respondJson(['ok' => true, 'user' => $u]);
    }

    private function getClientIp(): string
    {
        $headers = [
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
        ];

        foreach ($headers as $header) {
            if (empty($_SERVER[$header])) {
                continue;
            }
            foreach (explode(',', (string)$_SERVER[$header]) as $ip) {
                $ip = trim($ip);
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }

        return (string)($_SERVER['REMOTE_ADDR'] ?? '');
    }

    public function registerDevice(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) {
            $this->respondJson(['ok' => false, 'error' => 'unauthorized'], 401);
            return;
        }

        $fcmToken = trim((string)($_POST['fcm_token'] ?? ''));
        $platform = trim((string)($_POST['platform'] ?? 'android'));
        $deviceId = trim((string)($_POST['device_id'] ?? ''));
        if ($fcmToken === '') {
            $this->respondJson(['ok' => false, 'error' => 'missing_fcm_token'], 400);
            return;
        }

        Notifier::ensureDevicesTable($pdo);
        $ins = $pdo->prepare('INSERT INTO user_devices (user_id, platform, device_id, fcm_token, created_at, last_seen_at) VALUES (?,?,?,?,NOW(),NOW())
                              ON DUPLICATE KEY UPDATE platform=VALUES(platform), device_id=VALUES(device_id), last_seen_at=NOW()');
        $ins->execute([(int)$u['id'], $platform ?: null, $deviceId ?: null, $fcmToken]);

        $this->respondJson(['ok' => true]);
    }

    public function assignedIncidents(): void
    {
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        // si pas technicien, renvoyer vide (ou autoriser admins)
        $role = $u['role_key'] ?? '';
        if (!in_array($role, ['technicien','technician','tech'], true)) {
            $this->respondJson(['ok'=>true,'incidents'=>[]]);
            return;
        }

        try {
            $st = $pdo->prepare('SELECT i.id, i.ticket_id, i.title, i.priority, i.declared_at,
                                        s.label as status_label, s.color as status_color, s.key_name as status_key,
                                        ia.assigned_at
                                 FROM incident_assignments ia
                                 JOIN incidents i ON i.id = ia.incident_id
                                 LEFT JOIN incident_statuses s ON s.id = i.status_id
                                 WHERE ia.user_id = ? AND (ia.active IS NULL OR ia.active = 1)
                                 ORDER BY ia.assigned_at DESC');
            $st->execute([(int)$u['id']]);
            $rows = $st->fetchAll(PDO::FETCH_ASSOC);
            foreach ($rows as &$r) {
                $r['id'] = (int)$r['id'];
            }
            $this->respondJson(['ok'=>true,'incidents'=>$rows]);
        } catch (\Throwable $e) {
            $this->respondJson(['ok'=>true,'incidents'=>[]]);
        }
    }

    public function notifications(): void
    {
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        Notifier::ensureTables($pdo);
        $st = $pdo->prepare('SELECT id, title, body, url, is_read, created_at FROM notifications WHERE user_id=? ORDER BY created_at DESC LIMIT 100');
        $st->execute([(int)$u['id']]);
        $rows = $st->fetchAll(PDO::FETCH_ASSOC);
        $this->respondJson(['ok'=>true,'notifications'=>$rows]);
    }

    public function notificationsUnreadCount(): void
    {
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        Notifier::ensureTables($pdo);
        $st = $pdo->prepare('SELECT COUNT(*) FROM notifications WHERE user_id=? AND is_read=0');
        $st->execute([(int)$u['id']]);
        $c = (int)($st->fetchColumn() ?: 0);
        $this->respondJson(['ok'=>true,'unread'=>$c]);
    }

    public function notificationsReadAll(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        Notifier::ensureTables($pdo);
        $pdo->prepare('UPDATE notifications SET is_read=1 WHERE user_id=?')->execute([(int)$u['id']]);
        $this->respondJson(['ok'=>true]);
    }

    // --- Traitement (lecture) ---

    public function treatmentGet(): void
    {
        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        $incidentId = (int)($_GET['id'] ?? 0);
        if (!$incidentId) { $this->respondJson(['ok'=>false,'error'=>'missing_id'], 400); return; }

        // Vérifier assignation si technicien
        if (($u['role_key'] ?? '') === 'technicien') {
            try {
                $c = $pdo->prepare('SELECT COUNT(*) FROM incident_assignments WHERE incident_id=? AND user_id=? AND active=1');
                $c->execute([$incidentId, (int)$u['id']]);
                if ((int)$c->fetchColumn() === 0) {
                    $this->respondJson(['ok'=>false,'error'=>'forbidden'], 403);
                    return;
                }
            } catch (\Throwable $e) {
                $this->respondJson(['ok'=>false,'error'=>'forbidden'], 403);
                return;
            }
        }

        // Incident
        $sql = "SELECT i.*, c.name as client_name, l.name as location_name, s.label as status_label, s.key_name as status_key, s.color as status_color
                FROM incidents i
                LEFT JOIN clients c ON c.id = i.client_id
                LEFT JOIN locations l ON l.id = i.location_id
                LEFT JOIN incident_statuses s ON s.id = i.status_id
                WHERE i.id=?";
        $st = $pdo->prepare($sql);
        $st->execute([$incidentId]);
        $incident = $st->fetch(PDO::FETCH_ASSOC);
        if (!$incident) { $this->respondJson(['ok'=>false,'error'=>'not_found'], 404); return; }

        // Rapport (dernier)
        $this->ensureTreatmentTables($pdo);
        $repSt = $pdo->prepare('SELECT * FROM incident_reports WHERE incident_id=? ORDER BY id DESC LIMIT 1');
        $repSt->execute([$incidentId]);
        $report = $repSt->fetch(PDO::FETCH_ASSOC) ?: null;

        $materials = [];
        $attachments = [];
        if ($report && !empty($report['id'])) {
            $m = $pdo->prepare('SELECT * FROM incident_materials WHERE report_id=? ORDER BY id ASC');
            $m->execute([(int)$report['id']]);
            $materials = $m->fetchAll(PDO::FETCH_ASSOC);

            $a = $pdo->prepare('SELECT * FROM incident_attachments WHERE report_id=? ORDER BY uploaded_at DESC');
            $a->execute([(int)$report['id']]);
            $attachments = $a->fetchAll(PDO::FETCH_ASSOC);
        }

        $this->respondJson(['ok'=>true,'incident'=>$incident,'report'=>$report,'materials'=>$materials,'attachments'=>$attachments]);
    }

    // --- Traitement (save) ---

    public function treatmentSave(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->respondJson(['ok' => false, 'error' => 'method_not_allowed'], 405);
            return;
        }

        $pdo = Database::pdo();
        $u = $this->findUserFromToken($pdo);
        if (!$u) { $this->respondJson(['ok'=>false,'error'=>'unauthorized'], 401); return; }

        $incidentId = (int)($_POST['incident_id'] ?? 0);
        if (!$incidentId) { $this->respondJson(['ok'=>false,'error'=>'missing_incident_id'], 400); return; }

        // Restriction technicien: doit être assigné
        if (($u['role_key'] ?? '') === 'technicien') {
            $c = $pdo->prepare('SELECT COUNT(*) FROM incident_assignments WHERE incident_id=? AND user_id=? AND active=1');
            $c->execute([$incidentId, (int)$u['id']]);
            if ((int)$c->fetchColumn() === 0) { $this->respondJson(['ok'=>false,'error'=>'forbidden'], 403); return; }
        }

        $this->ensureTreatmentTables($pdo);

        // Inputs principaux (mêmes noms que incidents/treatment)
        $teamName = trim($_POST['team_name'] ?? ($u['name'] ?? ''));
        $teamContact = trim($_POST['team_contact'] ?? '');
        $typeOfIncident = trim($_POST['type_of_incident'] ?? '');
        $detectionMode = trim($_POST['detection_mode'] ?? '');
        $cutKm = isset($_POST['cut_distance_km']) ? (float)$_POST['cut_distance_km'] : null;
        $gpsLat = isset($_POST['gps_lat']) ? (float)str_replace(',', '.', (string)$_POST['gps_lat']) : null;
        $gpsLng = isset($_POST['gps_lng']) ? (float)str_replace(',', '.', (string)$_POST['gps_lng']) : null;
        $faultNature = trim($_POST['fault_nature'] ?? '');
        $equipments = $_POST['impacted_equipment'] ?? [];
        $equipmentsStr = is_array($equipments) ? json_encode(array_values($equipments), JSON_UNESCAPED_UNICODE) : null;
        $takeover = $_POST['takeover_at'] ?? null;
        $start = $_POST['intervention_start'] ?? null;
        $end = $_POST['intervention_end'] ?? null;
        $repairType = trim($_POST['repair_type'] ?? '');
        $workComments = trim($_POST['work_comments'] ?? '');
        $otdrResult = trim($_POST['otdr_result'] ?? '');
        $resolutionStatus = trim($_POST['resolution_status'] ?? '');
        $needAdditional = isset($_POST['need_additional']) ? (int)$_POST['need_additional'] : 0;
        $action = $_POST['action_type'] ?? 'draft';

        $durationHours = null;
        if ($start && $end) {
            $s = \DateTime::createFromFormat('Y-m-d\\TH:i', $start);
            $e = \DateTime::createFromFormat('Y-m-d\\TH:i', $end);
            if ($s && $e) {
                $diff = $e->getTimestamp() - $s->getTimestamp();
                if ($diff > 0) { $durationHours = round($diff / 3600, 2); }
            }
        }

        $publicRoot = realpath(__DIR__ . '/../../public');
        $baseDir = $publicRoot . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'incidents' . DIRECTORY_SEPARATOR . $incidentId;
        if (!is_dir($baseDir)) { @mkdir($baseDir, 0777, true); }

        $otdrBeforePath = $this->handleUpload('otdr_before', $baseDir);
        $otdrAfterPath = $this->handleUpload('otdr_after', $baseDir);
        $quotePath = $this->handleUpload('quote_file', $baseDir);

        // Signature base64
        $signaturePath = null;
        if (!empty($_POST['signature_data'])) {
            $signatureData = (string)$_POST['signature_data'];
            if (preg_match('/^data:image\/(\w+);base64,(.+)$/', $signatureData, $matches)) {
                $imageType = $matches[1];
                $base64Data = $matches[2];
                $imageData = base64_decode($base64Data);
                if ($imageData !== false) {
                    $safeName = 'signature_' . uniqid() . '.' . $imageType;
                    $dest = $baseDir . DIRECTORY_SEPARATOR . $safeName;
                    if (file_put_contents($dest, $imageData) !== false) {
                        $signaturePath = 'incidents/' . $incidentId . '/' . $safeName;
                    }
                }
            }
        }

        // Upsert report
        $stmt = $pdo->prepare('SELECT id FROM incident_reports WHERE incident_id=? ORDER BY id DESC LIMIT 1');
        $stmt->execute([$incidentId]);
        $reportId = (int)($stmt->fetchColumn() ?: 0);

        if ($reportId) {
            $up = $pdo->prepare('UPDATE incident_reports SET technician_id=?, team_name=?, team_contact=?, type_of_incident=?, detection_mode=?, cut_distance_km=?, gps_lat=?, gps_lng=?, fault_nature=?, impacted_equipment=?, takeover_at=?, intervention_start=?, intervention_end=?, duration_hours=?, repair_type=?, work_comments=?, otdr_before_path = COALESCE(?, otdr_before_path), otdr_after_path = COALESCE(?, otdr_after_path), otdr_result=?, conformity_status=?, resolution_status=?, need_additional=?, quote_file_path=COALESCE(?, quote_file_path), signature_path=COALESCE(?, signature_path), submitted_at = CASE WHEN ?=\'submit\' THEN NOW() ELSE submitted_at END, updated_at=NOW() WHERE id=?');
            $up->execute([
                (int)$u['id'], $teamName, $teamContact, $typeOfIncident, $detectionMode, $cutKm, $gpsLat, $gpsLng, $faultNature, $equipmentsStr,
                $takeover ? str_replace('T',' ',$takeover).':00' : null,
                $start ? str_replace('T',' ',$start).':00' : null,
                $end ? str_replace('T',' ',$end).':00' : null,
                $durationHours, $repairType, $workComments,
                $otdrBeforePath, $otdrAfterPath, $otdrResult, ($otdrResult==='Conforme'?'Conforme':($otdrResult==='Non conforme'?'Non conforme':null)), $resolutionStatus, $needAdditional, $quotePath, $signaturePath,
                $action, $reportId
            ]);
        } else {
            $ins = $pdo->prepare('INSERT INTO incident_reports (incident_id, technician_id, team_name, team_contact, type_of_incident, detection_mode, cut_distance_km, gps_lat, gps_lng, fault_nature, impacted_equipment, takeover_at, intervention_start, intervention_end, duration_hours, repair_type, work_comments, otdr_before_path, otdr_after_path, otdr_result, conformity_status, resolution_status, need_additional, quote_file_path, signature_path, submitted_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, CASE WHEN ?=\'submit\' THEN NOW() ELSE NULL END, NOW(), NOW())');
            $ins->execute([
                $incidentId, (int)$u['id'], $teamName, $teamContact, $typeOfIncident, $detectionMode, $cutKm, $gpsLat, $gpsLng, $faultNature, $equipmentsStr,
                $takeover ? str_replace('T',' ',$takeover).':00' : null,
                $start ? str_replace('T',' ',$start).':00' : null,
                $end ? str_replace('T',' ',$end).':00' : null,
                $durationHours, $repairType, $workComments, $otdrBeforePath, $otdrAfterPath, $otdrResult, ($otdrResult==='Conforme'?'Conforme':($otdrResult==='Non conforme'?'Non conforme':null)), $resolutionStatus, $needAdditional, $quotePath, $signaturePath,
                $action
            ]);
            $reportId = (int)$pdo->lastInsertId();
        }

        // materials replace
        $pdo->prepare('DELETE FROM incident_materials WHERE report_id=?')->execute([$reportId]);
        $m_des = $_POST['materials_designation'] ?? [];
        $m_qty = $_POST['materials_qty'] ?? [];
        $m_ref = $_POST['materials_reference'] ?? [];
        $m_cost = $_POST['materials_unit_cost'] ?? [];
        $matIns = $pdo->prepare('INSERT INTO incident_materials (report_id, designation, qty, reference, unit_cost) VALUES (?,?,?,?,?)');
        for ($i=0; $i < count($m_des); $i++) {
            $des = trim($m_des[$i] ?? ''); if ($des==='') continue;
            $qty = (float)($m_qty[$i] ?? 0);
            $ref = trim($m_ref[$i] ?? '');
            $uc = (float)($m_cost[$i] ?? 0);
            $matIns->execute([$reportId, $des, $qty, $ref, $uc]);
        }

        // photos[]
        if (!empty($_FILES['photos']['name']) && is_array($_FILES['photos']['name'])) {
            $attIns = $pdo->prepare('INSERT INTO incident_attachments (report_id, type, path, uploaded_at) VALUES (?,?,?,NOW())');
            $count = count($_FILES['photos']['name']);
            for ($i=0; $i<$count; $i++) {
                $p = $this->handleUploadArray('photos', $baseDir, $i);
                if ($p) { $attIns->execute([$reportId, 'photo', $p]); }
            }
        }

        // intervention photos
        if (!empty($_FILES['interv_photo']['name']) && is_array($_FILES['interv_photo']['name'])) {
            $count = count($_FILES['interv_photo']['name']);
            $obsArr = $_POST['interv_obs'] ?? [];
            $latArr = $_POST['interv_lat'] ?? [];
            $lngArr = $_POST['interv_lng'] ?? [];
            $takenAtArr = $_POST['interv_taken_at'] ?? [];
            $insPh = $pdo->prepare('INSERT INTO incident_attachments (report_id, type, path, observation, lat, lng, taken_by, taken_at, uploaded_at) VALUES (?,?,?,?,?,?,?,?,NOW())');
            for ($i=0; $i<$count; $i++) {
                $p = $this->handleUploadArray('interv_photo', $baseDir, $i);
                if (!$p) { continue; }
                $obs = isset($obsArr[$i]) ? trim((string)$obsArr[$i]) : null;
                $lat = isset($latArr[$i]) && $latArr[$i] !== '' ? (float)str_replace(',', '.', (string)$latArr[$i]) : null;
                $lng = isset($lngArr[$i]) && $lngArr[$i] !== '' ? (float)str_replace(',', '.', (string)$lngArr[$i]) : null;
                $takenBy = $u['name'] ?? null;
                $takenAt = null;
                if (!empty($takenAtArr[$i])) {
                    $d = \DateTime::createFromFormat('Y-m-d\\TH:i', (string)$takenAtArr[$i]);
                    if ($d) { $takenAt = $d->format('Y-m-d H:i:00'); }
                }
                $insPh->execute([$reportId, 'intervention_photo', $p, ($obs ?: null), $lat, $lng, $takenBy, $takenAt]);
            }
        }

        // notifications si submit
        if ($action === 'submit') {
            try {
                $iStmt = $pdo->prepare('SELECT ticket_id, title FROM incidents WHERE id=?');
                $iStmt->execute([$incidentId]);
                $i = $iStmt->fetch();
                $ticket = $i['ticket_id'] ?? ('INC-' . $incidentId);
                $titleN = 'Traitement soumis: ' . $ticket;
                $bodyN = ($u['name'] ?? 'Un utilisateur') . ' a soumis un rapport de traitement pour l\'incident ' . $ticket . '.';
                $url = \route_url('/incidents/treatment', ['id'=>$incidentId,'view'=>1]);
                $rec = $pdo->query("SELECT id FROM users WHERE active=1 AND role_key IN ('superviseur','supervisor','manager','admin')")->fetchAll(PDO::FETCH_COLUMN);
                if (!empty($rec)) {
                    Notifier::notifyUsers($pdo, array_map('intval', $rec), $titleN, $bodyN, $url);
                    Notifier::pushUsers($pdo, array_map('intval', $rec), $titleN, $bodyN, $url);
                }
            } catch (\Throwable $e) { /* ignore */ }
        }

        $this->respondJson(['ok'=>true,'incident_id'=>$incidentId,'report_id'=>$reportId,'submitted'=>($action==='submit')]);
    }

    // --- Helpers DB/schema & upload (copie minimale depuis IncidentsController) ---

    private function ensureColumn(PDO $pdo, string $table, string $column, string $definition): void
    {
        try {
            $db = $pdo->query('SELECT DATABASE()')->fetchColumn();
            if (!$db) { return; }
            $chk = $pdo->prepare('SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=? AND TABLE_NAME=? AND COLUMN_NAME=?');
            $chk->execute([$db, $table, $column]);
            if ((int)$chk->fetchColumn() === 0) {
                $pdo->exec("ALTER TABLE `{$table}` ADD COLUMN {$definition}");
            }
        } catch (\Throwable $e) {
            // ignore
        }
    }

    private function ensureTreatmentTables(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS incident_reports (
            id INT AUTO_INCREMENT PRIMARY KEY,
            incident_id INT NOT NULL,
            technician_id INT NOT NULL,
            team_name VARCHAR(255) NULL,
            team_contact VARCHAR(255) NULL,
            type_of_incident VARCHAR(50) NULL,
            detection_mode VARCHAR(50) NULL,
            cut_distance_km DECIMAL(10,2) NULL,
            gps_lat DECIMAL(10,8) NULL,
            gps_lng DECIMAL(11,8) NULL,
            fault_nature TEXT NULL,
            impacted_equipment TEXT NULL,
            takeover_at DATETIME NULL,
            intervention_start DATETIME NULL,
            intervention_end DATETIME NULL,
            duration_hours DECIMAL(10,2) NULL,
            repair_type VARCHAR(100) NULL,
            work_comments TEXT NULL,
            otdr_before_path VARCHAR(255) NULL,
            otdr_after_path VARCHAR(255) NULL,
            otdr_result VARCHAR(20) NULL,
            conformity_status VARCHAR(20) NULL,
            resolution_status VARCHAR(20) NULL,
            need_additional TINYINT(1) DEFAULT 0,
            quote_file_path VARCHAR(255) NULL,
            supervisor_comments TEXT NULL,
            signature_path VARCHAR(255) NULL,
            submitted_at DATETIME NULL,
            validated_at DATETIME NULL,
            validated_by INT NULL,
            rejected_at DATETIME NULL,
            rejected_by INT NULL,
            rejection_reason TEXT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        $this->ensureColumn($pdo, 'incident_reports', 'type_of_incident', '`type_of_incident` VARCHAR(50) NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'takeover_at', '`takeover_at` DATETIME NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'conformity_status', '`conformity_status` VARCHAR(20) NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'validated_at', '`validated_at` DATETIME NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'validated_by', '`validated_by` INT NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'rejected_at', '`rejected_at` DATETIME NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'rejected_by', '`rejected_by` INT NULL');
        $this->ensureColumn($pdo, 'incident_reports', 'rejection_reason', '`rejection_reason` TEXT NULL');

        $pdo->exec("CREATE TABLE IF NOT EXISTS incident_materials (
            id INT AUTO_INCREMENT PRIMARY KEY,
            report_id INT NOT NULL,
            designation VARCHAR(255) NOT NULL,
            qty DECIMAL(10,2) DEFAULT 0,
            reference VARCHAR(255) NULL,
            unit_cost DECIMAL(10,2) DEFAULT 0
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        $pdo->exec("CREATE TABLE IF NOT EXISTS incident_attachments (
            id INT AUTO_INCREMENT PRIMARY KEY,
            report_id INT NOT NULL,
            type VARCHAR(20) NOT NULL,
            path VARCHAR(255) NOT NULL,
            uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        $this->ensureColumn($pdo, 'incident_attachments', 'observation', '`observation` TEXT NULL');
        $this->ensureColumn($pdo, 'incident_attachments', 'lat', '`lat` DECIMAL(10,7) NULL');
        $this->ensureColumn($pdo, 'incident_attachments', 'lng', '`lng` DECIMAL(11,7) NULL');
        $this->ensureColumn($pdo, 'incident_attachments', 'taken_by', '`taken_by` VARCHAR(255) NULL');
        $this->ensureColumn($pdo, 'incident_attachments', 'taken_at', '`taken_at` DATETIME NULL');
    }

    private function handleUpload(string $field, string $baseDir): ?string
    {
        if (!isset($_FILES[$field]) || !is_uploaded_file($_FILES[$field]['tmp_name'])) { return null; }
        $name = $_FILES[$field]['name'];
        $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
        $safe = uniqid($field.'_') . '.' . $ext;
        $dest = $baseDir . DIRECTORY_SEPARATOR . $safe;
        if (@move_uploaded_file($_FILES[$field]['tmp_name'], $dest)) {
            $incidentId = basename(dirname($dest));
            return 'incidents/' . $incidentId . '/' . basename($dest);
        }
        return null;
    }

    private function handleUploadArray(string $field, string $baseDir, int $index): ?string
    {
        if (!isset($_FILES[$field]['tmp_name'][$index]) || !is_uploaded_file($_FILES[$field]['tmp_name'][$index])) { return null; }
        $name = $_FILES[$field]['name'][$index];
        $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
        $safe = uniqid($field.'_') . '.' . $ext;
        $dest = $baseDir . DIRECTORY_SEPARATOR . $safe;
        if (@move_uploaded_file($_FILES[$field]['tmp_name'][$index], $dest)) {
            $incidentId = basename(dirname($dest));
            return 'incidents/' . $incidentId . '/' . basename($dest);
        }
        return null;
    }
}
