<?php
require_once __DIR__ . '/config.php';

function db(): PDO {
    static $pdo = null;
    if ($pdo) return $pdo;
    $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHARSET;
    $pdo = new PDO($dsn, DB_USER, DB_PASS, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
    return $pdo;
}

function json_response($data, int $code = 200): void {
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function ensure_upload_dirs(): void {
    foreach ([UPLOAD_DIR, UPLOAD_DIR . '/numerales', UPLOAD_DIR . '/observaciones', PDF_DIR] as $dir) {
        if (!is_dir($dir)) mkdir($dir, 0775, true);
    }
}

function app_setting(string $key, $default = null) {
    $stmt = db()->prepare('SELECT setting_value FROM settings WHERE setting_key = ? LIMIT 1');
    $stmt->execute([$key]);
    $row = $stmt->fetch();
    return $row ? $row['setting_value'] : $default;
}

function set_app_setting(string $key, string $value): void {
    $stmt = db()->prepare('INSERT INTO settings(setting_key, setting_value) VALUES(?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value), updated_at = CURRENT_TIMESTAMP');
    $stmt->execute([$key, $value]);
}

function require_login(): void {
    if (session_status() !== PHP_SESSION_ACTIVE) session_start();
    if (empty($_SESSION['logged_in'])) json_response(['ok' => false, 'error' => 'No autorizado'], 401);
}

function save_base64_image(?string $base64, string $subdir, string $prefix): ?string {
    if (!$base64) return null;
    if (!preg_match('/^data:image\/(png|jpeg|jpg|webp);base64,/', $base64, $m)) return null;
    $ext = $m[1] === 'jpeg' ? 'jpg' : $m[1];
    $data = preg_replace('/^data:image\/(png|jpeg|jpg|webp);base64,/', '', $base64);
    $binary = base64_decode($data);
    if ($binary === false) return null;
    ensure_upload_dirs();
    $name = $prefix . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
    $relative = 'uploads/' . trim($subdir, '/') . '/' . $name;
    file_put_contents(__DIR__ . '/' . $relative, $binary);
    return $relative;
}

function public_url(string $relativePath = ''): string {
    $base = BASE_URL;
    if (!$base) {
        $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['SERVER_PORT'] ?? '') == 443);
        $scheme = $https ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        $dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '')), '/');
        $base = $scheme . '://' . $host . ($dir ? $dir : '');
    }
    return rtrim($base, '/') . '/' . ltrim($relativePath, '/');
}

function review_type_label(string $type): string {
    switch ($type) {
        case 'surtidores': return 'Revisión diaria de surtidores';
        case 'generador': return 'Revisión semanal generador';
        case 'lavado': return 'Revisión lavado y aspirado';
        default: return 'Revisión operacional';
    }
}

function pdf_to_cp1252(string $s): string {
    $converted = @iconv('UTF-8', 'Windows-1252//TRANSLIT//IGNORE', $s);
    return $converted === false ? preg_replace('/[^\x20-\x7E]/', '', $s) : $converted;
}

function pdf_escape(string $s): string {
    $s = pdf_to_cp1252($s);
    return str_replace(['\\', '(', ')', "\r", "\n"], ['\\\\', '\\(', '\\)', ' ', ' '], $s);
}

function pdf_bool($value): string {
    return !empty($value) ? 'Sí' : 'No';
}

function normalize_image_for_pdf(?string $relativePath): ?array {
    if (!$relativePath) return null;
    $relativePath = ltrim($relativePath, '/');
    $abs = __DIR__ . '/' . $relativePath;
    if (!is_file($abs)) return null;
    $info = @getimagesize($abs);
    if (!$info) return null;
    $mime = $info['mime'] ?? '';
    if ($mime === 'image/jpeg' || $mime === 'image/jpg') {
        return [
            'data' => file_get_contents($abs),
            'width' => (int)$info[0],
            'height' => (int)$info[1],
            'colorspace' => (($info['channels'] ?? 3) === 1) ? '/DeviceGray' : '/DeviceRGB',
            'filter' => '/DCTDecode'
        ];
    }
    // Para PNG/WebP/firma desde canvas, convertimos a JPG si GD está disponible.
    if (function_exists('imagecreatefromstring') && function_exists('imagejpeg')) {
        $raw = @file_get_contents($abs);
        $src = @imagecreatefromstring($raw);
        if (!$src) return null;
        $w = imagesx($src); $h = imagesy($src);
        $canvas = imagecreatetruecolor($w, $h);
        $white = imagecolorallocate($canvas, 255, 255, 255);
        imagefilledrectangle($canvas, 0, 0, $w, $h, $white);
        imagecopy($canvas, $src, 0, 0, 0, 0, $w, $h);
        ensure_upload_dirs();
        $tmp = PDF_DIR . '/pdfimg_' . bin2hex(random_bytes(5)) . '.jpg';
        imagejpeg($canvas, $tmp, 88);
        imagedestroy($src); imagedestroy($canvas);
        return [
            'data' => file_get_contents($tmp),
            'width' => $w,
            'height' => $h,
            'colorspace' => '/DeviceRGB',
            'filter' => '/DCTDecode'
        ];
    }
    return null;
}

class ReportPDF {
    private float $w = 612;
    private float $h = 792;
    private array $pages = [];
    private array $images = [];
    private int $imageSeq = 1;
    public float $y = 40;

    public function __construct() { $this->addPage(); }

    public function addPage(): void {
        $this->pages[] = ['content' => '', 'xobjects' => []];
        $this->y = 40;
    }

    private function currentPageIndex(): int { return count($this->pages) - 1; }

    private function addRaw(string $raw): void {
        $idx = $this->currentPageIndex();
        $this->pages[$idx]['content'] .= $raw;
    }

    public function ensureSpace(float $needed): void {
        if ($this->y + $needed > $this->h - 45) $this->addPage();
    }

    private function rgb(array $rgb): string {
        return sprintf('%.3F %.3F %.3F rg ', $rgb[0]/255, $rgb[1]/255, $rgb[2]/255);
    }

    public function rect(float $x, float $yTop, float $width, float $height, array $fill = [255,255,255]): void {
        $y = $this->h - $yTop - $height;
        $this->addRaw('q ' . $this->rgb($fill) . sprintf('%.2F %.2F %.2F %.2F re f Q' . "\n", $x, $y, $width, $height));
    }

    public function line(float $x1, float $y1Top, float $x2, float $y2Top, array $color = [220,225,232]): void {
        $y1 = $this->h - $y1Top; $y2 = $this->h - $y2Top;
        $this->addRaw('q ' . sprintf('%.3F %.3F %.3F RG ', $color[0]/255, $color[1]/255, $color[2]/255) . sprintf('%.2F %.2F m %.2F %.2F l S Q' . "\n", $x1, $y1, $x2, $y2));
    }

    public function text(string $text, float $x, float $yTop, float $size = 10, bool $bold = false, array $color = [15,23,42]): void {
        $font = $bold ? '/F2' : '/F1';
        $baseline = $this->h - $yTop - $size;
        $this->addRaw('BT ' . $this->rgb($color) . sprintf('%s %.2F Tf 1 0 0 1 %.2F %.2F Tm (%s) Tj ET' . "\n", $font, $size, $x, $baseline, pdf_escape($text)));
    }

    public function multiline(string $text, float $x, float $yTop, float $maxWidth, float $size = 10, bool $bold = false, array $color = [15,23,42], float $lineHeight = 14): float {
        $text = trim(preg_replace('/\s+/', ' ', $text));
        if ($text === '') $text = '-';
        $maxChars = max(18, (int)floor($maxWidth / ($size * 0.50)));
        $words = explode(' ', $text);
        $lines = [];
        $line = '';
        foreach ($words as $word) {
            if (strlen(pdf_to_cp1252(trim($line . ' ' . $word))) > $maxChars && $line !== '') {
                $lines[] = $line;
                $line = $word;
            } else {
                $line = trim($line . ' ' . $word);
            }
        }
        if ($line !== '') $lines[] = $line;
        $y = $yTop;
        foreach ($lines as $ln) {
            $this->ensureSpace($lineHeight + 2);
            $this->text($ln, $x, $y, $size, $bold, $color);
            $y += $lineHeight;
            $this->y = max($this->y, $y);
        }
        return $y;
    }

    public function labelValue(string $label, string $value, float $x, float $width): void {
        $this->ensureSpace(24);
        $this->rect($x, $this->y, $width, 24, [248,250,252]);
        $this->text($label, $x + 10, $this->y + 6, 8, true, [71,85,105]);
        $this->multiline($value, $x + 150, $this->y + 6, $width - 160, 9.5, false, [15,23,42], 12);
        $this->y += 26;
    }

    public function section(string $title): void {
        $this->ensureSpace(34);
        $this->y += 8;
        $this->rect(40, $this->y, 532, 25, [239,246,255]);
        $this->text($title, 52, $this->y + 7, 12, true, [30,64,175]);
        $this->y += 34;
    }

    public function image(?string $relativePath, float $x, float $yTop, float $boxW, float $boxH): bool {
        $img = normalize_image_for_pdf($relativePath);
        if (!$img) return false;
        $name = 'Im' . $this->imageSeq++;
        $this->images[$name] = $img;
        $idx = $this->currentPageIndex();
        $this->pages[$idx]['xobjects'][$name] = true;
        $scale = min($boxW / $img['width'], $boxH / $img['height']);
        $drawW = $img['width'] * $scale;
        $drawH = $img['height'] * $scale;
        $drawX = $x + ($boxW - $drawW) / 2;
        $drawY = $this->h - $yTop - $drawH;
        $this->addRaw(sprintf("q %.2F 0 0 %.2F %.2F %.2F cm /%s Do Q\n", $drawW, $drawH, $drawX, $drawY, $name));
        return true;
    }

    public function output(string $filePath): void {
        $objects = [];
        $objects[] = '<< /Type /Catalog /Pages 2 0 R >>';
        $objects[] = ''; // Pages placeholder
        $objects[] = '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>';
        $objects[] = '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>';

        $imageObj = [];
        foreach ($this->images as $name => $img) {
            $objNo = count($objects) + 1;
            $imageObj[$name] = $objNo;
            $objects[] = "<< /Type /XObject /Subtype /Image /Width {$img['width']} /Height {$img['height']} /ColorSpace {$img['colorspace']} /BitsPerComponent 8 /Filter {$img['filter']} /Length " . strlen($img['data']) . " >>\nstream\n" . $img['data'] . "\nendstream";
        }

        $pageRefs = [];
        foreach ($this->pages as $page) {
            $content = $page['content'];
            $contentObj = count($objects) + 1;
            $objects[] = "<< /Length " . strlen($content) . " >>\nstream\n$content\nendstream";
            $xobj = '';
            foreach (array_keys($page['xobjects']) as $name) {
                if (isset($imageObj[$name])) $xobj .= "/$name {$imageObj[$name]} 0 R ";
            }
            $resources = "<< /Font << /F1 3 0 R /F2 4 0 R >>" . ($xobj ? " /XObject << $xobj >>" : '') . " >>";
            $pageObj = count($objects) + 1;
            $objects[] = "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {$this->w} {$this->h}] /Resources $resources /Contents $contentObj 0 R >>";
            $pageRefs[] = $pageObj . ' 0 R';
        }
        $objects[1] = '<< /Type /Pages /Kids [' . implode(' ', $pageRefs) . '] /Count ' . count($pageRefs) . ' >>';

        $pdf = "%PDF-1.4\n%\xE2\xE3\xCF\xD3\n";
        $offsets = [0];
        foreach ($objects as $i => $obj) {
            $offsets[$i+1] = strlen($pdf);
            $pdf .= ($i+1) . " 0 obj\n" . $obj . "\nendobj\n";
        }
        $xref = strlen($pdf);
        $pdf .= "xref\n0 " . (count($objects)+1) . "\n0000000000 65535 f \n";
        for ($i=1; $i<=count($objects); $i++) $pdf .= sprintf("%010d 00000 n \n", $offsets[$i]);
        $pdf .= "trailer\n<< /Size " . (count($objects)+1) . " /Root 1 0 R >>\nstartxref\n$xref\n%%EOF";
        file_put_contents($filePath, $pdf);
    }
}

function add_report_header(ReportPDF $pdf, string $station, string $title, int $reviewId): void {
    $pdf->rect(0, 0, 612, 82, [15, 23, 42]);
    $pdf->rect(40, 22, 38, 38, [37, 99, 235]);
    $pdf->text('CO', 51, 34, 12, true, [255,255,255]);
    $pdf->text('SISTEMA DE CONTROL OPERACIONAL', 92, 22, 9, true, [147,197,253]);
    $pdf->text($station, 92, 39, 18, true, [255,255,255]);
    $pdf->text('Registro N° ' . $reviewId, 460, 34, 12, true, [255,255,255]);
    $pdf->y = 102;
    $pdf->text($title, 40, $pdf->y, 18, true, [15,23,42]);
    $pdf->y += 32;
}

function add_basic_info(ReportPDF $pdf, int $reviewId, string $date, string $responsible, string $type): void {
    $pdf->section('Datos generales');
    $pdf->labelValue('Tipo de revisión', review_type_label($type), 40, 532);
    $pdf->labelValue('Registro', 'N° ' . $reviewId, 40, 532);
    $pdf->labelValue('Fecha revisión', $date, 40, 532);
    $pdf->labelValue('Responsable', $responsible, 40, 532);
    $pdf->labelValue('Fecha generación', date('Y-m-d H:i:s'), 40, 532);
}

function add_signature(ReportPDF $pdf, ?string $signaturePath): void {
    $pdf->section('Firma responsable');
    $pdf->rect(40, $pdf->y, 260, 82, [248,250,252]);
    if ($signaturePath && $pdf->image($signaturePath, 50, $pdf->y + 8, 240, 54)) {
        $pdf->line(50, $pdf->y + 64, 290, $pdf->y + 64, [148,163,184]);
        $pdf->text('Firma registrada digitalmente', 88, $pdf->y + 68, 8, false, [71,85,105]);
    } else {
        $pdf->text('Firma registrada en el sistema.', 52, $pdf->y + 30, 10, false, [71,85,105]);
    }
    $pdf->y += 96;
}

function add_lavado_report(ReportPDF $pdf, array $data): void {
    $fichasLav = (int)($data['fichas_lavado'] ?? 0);
    $fichasAsp = (int)($data['fichas_aspirado'] ?? 0);
    $pdf->section('Lavado y aspirado');
    $pdf->labelValue('Numeral lavado del día', (string)($data['numeral_lavado'] ?? '-'), 40, 532);
    $pdf->labelValue('Numeral aspirado del día', (string)($data['numeral_aspirado'] ?? '-'), 40, 532);
    $pdf->labelValue('Fichas retiradas lavado', (string)$fichasLav, 40, 532);
    $pdf->labelValue('Fichas retiradas aspirado', (string)$fichasAsp, 40, 532);
    $pdf->labelValue('Total fichas retiradas', (string)($fichasLav + $fichasAsp), 40, 532);
    $pdf->labelValue('Incidente o problema presente', pdf_bool($data['incidente'] ?? false), 40, 532);
    $inspeccion = $data['inspeccion'] ?? [];
    $pdf->labelValue('Inspección visual OK', is_array($inspeccion) && $inspeccion ? implode(', ', $inspeccion) : '-', 40, 532);
    $pdf->labelValue('Observaciones', (string)($data['observaciones'] ?? '-'), 40, 532);

    $pdf->section('Fotos de numerales');
    $pdf->ensureSpace(195);
    $top = $pdf->y;
    $pdf->rect(40, $top, 250, 170, [248,250,252]);
    $pdf->rect(322, $top, 250, 170, [248,250,252]);
    $pdf->text('Numeral lavado', 52, $top + 10, 11, true, [15,23,42]);
    $pdf->text('Numeral aspirado', 334, $top + 10, 11, true, [15,23,42]);
    if (!$pdf->image($data['foto_numeral_lavado_path'] ?? null, 52, $top + 30, 226, 122)) {
        $pdf->text('Foto registrada, no disponible para incrustar.', 52, $top + 74, 9, false, [100,116,139]);
    }
    if (!$pdf->image($data['foto_numeral_aspirado_path'] ?? null, 334, $top + 30, 226, 122)) {
        $pdf->text('Foto registrada, no disponible para incrustar.', 334, $top + 74, 9, false, [100,116,139]);
    }
    $pdf->y = $top + 184;

    if (!empty($data['fotos_observacion_paths']) && is_array($data['fotos_observacion_paths'])) {
        $pdf->section('Fotos de observación');
        foreach ($data['fotos_observacion_paths'] as $idx => $path) {
            $pdf->ensureSpace(160);
            $pdf->text('Foto observación ' . ($idx + 1), 40, $pdf->y, 10, true, [15,23,42]);
            $pdf->image($path, 40, $pdf->y + 18, 260, 130);
            $pdf->y += 162;
        }
    }
}

function add_generador_report(ReportPDF $pdf, array $data): void {
    $pdf->section('Generador');
    $pdf->labelValue('Horómetro', (string)($data['horometro'] ?? '-'), 40, 532);
    $pdf->labelValue('Minutos de prueba', (string)($data['minutos'] ?? '-'), 40, 532);
    $checks = $data['checks'] ?? [];
    $pdf->labelValue('Puntos revisados', is_array($checks) && $checks ? implode(', ', $checks) : '-', 40, 532);
    $pdf->labelValue('Observaciones', (string)($data['observaciones'] ?? '-'), 40, 532);
}

function add_surtidores_report(ReportPDF $pdf, array $data): void {
    $pdf->section('Detalle surtidores');
    $items = $data['items'] ?? [];
    if (!is_array($items) || !$items) {
        $pdf->labelValue('Detalle', 'No se registraron ítems detallados en esta revisión.', 40, 532);
        return;
    }
    foreach ($items as $idx => $item) {
        $checks = $item['checks'] ?? [];
        $txt = 'Surtidor: ' . ($item['surtidor'] ?? '-') . ' | Cara: ' . ($item['cara'] ?? '-') . ' | Estado: ' . (is_array($checks) && $checks ? implode(', ', $checks) : '-') . ' | Observación: ' . ($item['observacion'] ?? '-');
        $pdf->ensureSpace(42);
        $pdf->rect(40, $pdf->y, 532, 36, [248,250,252]);
        $pdf->multiline($txt, 52, $pdf->y + 8, 500, 9, false, [15,23,42], 12);
        $pdf->y += 40;
    }
}

function generate_review_pdf(int $reviewId, string $type, string $date, string $responsible, array $data, ?string $signaturePath): string {
    ensure_upload_dirs();
    $relative = 'uploads/pdfs/revision_' . $reviewId . '_' . date('Ymd_His') . '.pdf';
    $filePath = __DIR__ . '/' . $relative;
    $station = app_setting('station_name', 'Copec Ogana 20830');
    $pdf = new ReportPDF();
    add_report_header($pdf, $station, review_type_label($type), $reviewId);
    add_basic_info($pdf, $reviewId, $date, $responsible, $type);
    if ($type === 'lavado') add_lavado_report($pdf, $data);
    elseif ($type === 'generador') add_generador_report($pdf, $data);
    elseif ($type === 'surtidores') add_surtidores_report($pdf, $data);
    else $pdf->labelValue('Datos', json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 40, 532);
    add_signature($pdf, $signaturePath);
    $pdf->section('Respaldo');
    $pdf->multiline('Documento generado automáticamente por el Sistema de Control Operacional. Este informe corresponde al respaldo interno de la revisión registrada en la aplicación.', 40, $pdf->y, 532, 9, false, [71,85,105], 13);
    $pdf->output($filePath);
    return $relative;
}

function smtp_read($fp): string {
    $data = '';
    while ($str = fgets($fp, 515)) {
        $data .= $str;
        if (isset($str[3]) && $str[3] === ' ') break;
    }
    return $data;
}

function smtp_cmd($fp, string $cmd, array $okCodes): string {
    fwrite($fp, $cmd . "\r\n");
    $resp = smtp_read($fp);
    $code = (int)substr($resp, 0, 3);
    if (!in_array($code, $okCodes, true)) throw new RuntimeException('SMTP error: ' . trim($resp));
    return $resp;
}

function send_smtp_mail(array $to, string $subject, string $html, array $attachments = []): array {
    $to = array_values(array_unique(array_filter(array_map('trim', $to), function($e) { return filter_var($e, FILTER_VALIDATE_EMAIL); })));
    if (!$to) return ['sent' => false, 'error' => 'No hay correos válidos configurados'];
    if (!SMTP_ENABLED) return ['sent' => false, 'error' => 'SMTP_ENABLED está en false'];

    $host = SMTP_HOST;
    $port = (int)SMTP_PORT;
    $secure = strtolower(SMTP_SECURE);
    $remote = ($secure === 'ssl' ? 'ssl://' : '') . $host;
    $fp = @stream_socket_client($remote . ':' . $port, $errno, $errstr, 30);
    if (!$fp) throw new RuntimeException("No se pudo conectar a SMTP: $errstr ($errno)");
    stream_set_timeout($fp, 30);
    smtp_read($fp);
    smtp_cmd($fp, 'EHLO ' . ($_SERVER['HTTP_HOST'] ?? 'localhost'), [250]);
    if ($secure === 'tls') {
        smtp_cmd($fp, 'STARTTLS', [220]);
        if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) throw new RuntimeException('No se pudo iniciar TLS SMTP');
        smtp_cmd($fp, 'EHLO ' . ($_SERVER['HTTP_HOST'] ?? 'localhost'), [250]);
    }
    if (SMTP_USER !== '') {
        smtp_cmd($fp, 'AUTH LOGIN', [334]);
        smtp_cmd($fp, base64_encode(SMTP_USER), [334]);
        smtp_cmd($fp, base64_encode(SMTP_PASS), [235]);
    }
    smtp_cmd($fp, 'MAIL FROM:<' . SMTP_FROM_EMAIL . '>', [250]);
    foreach ($to as $email) smtp_cmd($fp, 'RCPT TO:<' . $email . '>', [250, 251]);
    smtp_cmd($fp, 'DATA', [354]);

    $boundary = '=_boundary_' . bin2hex(random_bytes(12));
    $headers = [];
    $headers[] = 'From: ' . mb_encode_mimeheader(SMTP_FROM_NAME, 'UTF-8') . ' <' . SMTP_FROM_EMAIL . '>';
    $headers[] = 'To: ' . implode(', ', $to);
    $headers[] = 'Subject: ' . mb_encode_mimeheader($subject, 'UTF-8');
    $headers[] = 'MIME-Version: 1.0';
    $headers[] = 'Content-Type: multipart/mixed; boundary="' . $boundary . '"';

    $body = implode("\r\n", $headers) . "\r\n\r\n";
    $body .= "--$boundary\r\n";
    $body .= "Content-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n";
    $body .= $html . "\r\n\r\n";
    foreach ($attachments as $file) {
        if (!is_file($file['path'])) continue;
        $name = $file['name'] ?? basename($file['path']);
        $mime = $file['mime'] ?? 'application/octet-stream';
        $content = chunk_split(base64_encode(file_get_contents($file['path'])));
        $body .= "--$boundary\r\n";
        $body .= "Content-Type: $mime; name=\"$name\"\r\n";
        $body .= "Content-Transfer-Encoding: base64\r\n";
        $body .= "Content-Disposition: attachment; filename=\"$name\"\r\n\r\n";
        $body .= $content . "\r\n";
    }
    $body .= "--$boundary--\r\n.";
    fwrite($fp, $body . "\r\n");
    $resp = smtp_read($fp);
    $code = (int)substr($resp, 0, 3);
    if ($code !== 250) throw new RuntimeException('SMTP error al enviar DATA: ' . trim($resp));
    smtp_cmd($fp, 'QUIT', [221]);
    fclose($fp);
    return ['sent' => true, 'error' => null];
}

function send_review_email(int $reviewId, string $type, string $date, string $responsible, ?string $responsibleEmail, string $pdfRelative): array {
    $emails = json_decode(app_setting('emails', '[]'), true) ?: [];
    if ($responsibleEmail && filter_var($responsibleEmail, FILTER_VALIDATE_EMAIL)) $emails[] = $responsibleEmail;
    $station = app_setting('station_name', 'Copec Ogana 20830');
    $subject = $station . ' - ' . review_type_label($type) . ' - ' . $date;
    $html = '<p>Estimados,</p>'
        . '<p>Se adjunta respaldo PDF de <b>' . htmlspecialchars(review_type_label($type)) . '</b>.</p>'
        . '<p><b>Fecha:</b> ' . htmlspecialchars($date) . '<br>'
        . '<b>Responsable:</b> ' . htmlspecialchars($responsible) . '<br>'
        . '<b>Registro:</b> ' . $reviewId . '</p>'
        . '<p>Este correo fue generado automáticamente por el Sistema de Control Operacional.</p>';
    $pdfPath = __DIR__ . '/' . $pdfRelative;
    return send_smtp_mail($emails, $subject, $html, [[
        'path' => $pdfPath,
        'name' => 'revision_' . $reviewId . '.pdf',
        'mime' => 'application/pdf'
    ]]);
}
