<?php
/**
 * Modul Analisa Margin Operasi BPJS
 * RS BaliMéd Denpasar
 * Native PHP + MySQL, tanpa dependency PhpSpreadsheet.
 */

declare(strict_types=1);

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

$conn = $conn ?? (function_exists('getConnection') ? getConnection() : null);
if (!$conn instanceof mysqli) {
    echo "<div class='p-4 rounded-xl bg-red-50 text-red-700 border border-red-200'>Koneksi database tidak tersedia.</div>";
    return;
}

if (!function_exists('bpjs_e')) {
    function bpjs_e($v): string { return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }
}
if (!function_exists('bpjs_money')) {
    function bpjs_money($v): string { return 'Rp ' . number_format((float)$v, 0, ',', '.'); }
}
if (!function_exists('bpjs_pct')) {
    function bpjs_pct($v): string { return number_format(((float)$v) * 100, 2, ',', '.') . '%'; }
}
if (!function_exists('bpjs_current_user_id')) {
    function bpjs_current_user_id(): int { return (int)($_SESSION['user_id'] ?? $_SESSION['user']['id'] ?? 0); }
}
if (!function_exists('bpjs_current_name')) {
    function bpjs_current_name(): string { return (string)($_SESSION['full_name'] ?? $_SESSION['user']['name'] ?? $_SESSION['username'] ?? 'User'); }
}

if (!function_exists('bpjs_table_exists')) {
    function bpjs_table_exists(mysqli $conn, string $table): bool
    {
        $tableEsc = $conn->real_escape_string($table);
        try {
            $res = $conn->query("SHOW TABLES LIKE '{$tableEsc}'");
            return $res && $res->num_rows > 0;
        } catch (Throwable $e) {
            return false;
        }
    }
}
if (!function_exists('bpjs_column_exists')) {
    function bpjs_column_exists(mysqli $conn, string $table, string $column): bool
    {
        $tableEsc = str_replace('`', '``', $table);
        $columnEsc = $conn->real_escape_string($column);
        try {
            $res = $conn->query("SHOW COLUMNS FROM `{$tableEsc}` LIKE '{$columnEsc}'");
            return $res && $res->num_rows > 0;
        } catch (Throwable $e) {
            return false;
        }
    }
}
if (!function_exists('bpjs_safe_query')) {
    function bpjs_safe_query(mysqli $conn, string $sql): void
    {
        try {
            $conn->query($sql);
        } catch (Throwable $e) {
            // Migrasi lama bisa sudah pernah dijalankan. Jangan matikan halaman karena duplicate column/index.
        }
    }
}

function bpjs_install_tables(mysqli $conn): void
{
    $conn->query("CREATE TABLE IF NOT EXISTS bpjs_margin_uploads (
        id INT AUTO_INCREMENT PRIMARY KEY,
        judul VARCHAR(200) NOT NULL,
        periode_bulan VARCHAR(30) NULL,
        periode_tahun INT NULL,
        file_name VARCHAR(255) NULL,
        original_file_name VARCHAR(255) NULL,
        total_rows INT DEFAULT 0,
        uploaded_by INT NULL,
        uploaded_by_name VARCHAR(150) NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    $conn->query("CREATE TABLE IF NOT EXISTS bpjs_margin_settings (
        id INT AUTO_INCREMENT PRIMARY KEY,
        kelas ENUM('Kelas 1','Kelas 2','Kelas 3') NOT NULL UNIQUE,
        threshold_persen DECIMAL(5,2) NOT NULL,
        reward_persen DECIMAL(5,2) NOT NULL DEFAULT 0,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    // Kolom baru untuk perhitungan terbaru: batas punishment/minimal dan reward/maksimal.
    // Aman untuk hosting yang sudah pernah menjalankan migrasi: cek kolom dulu agar tidak fatal duplicate column.
    if (!bpjs_column_exists($conn, 'bpjs_margin_settings', 'reward_persen')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_settings ADD COLUMN reward_persen DECIMAL(5,2) NOT NULL DEFAULT 0 AFTER threshold_persen");
    }

    $conn->query("INSERT IGNORE INTO bpjs_margin_settings (kelas, threshold_persen, reward_persen) VALUES
        ('Kelas 1', 35.00, 40.00), ('Kelas 2', 25.00, 35.00), ('Kelas 3', 20.00, 25.00)");
    $conn->query("UPDATE bpjs_margin_settings SET threshold_persen=35.00, reward_persen=40.00 WHERE kelas='Kelas 1' AND (threshold_persen<>35.00 OR reward_persen=0)");
    $conn->query("UPDATE bpjs_margin_settings SET threshold_persen=25.00, reward_persen=35.00 WHERE kelas='Kelas 2' AND (threshold_persen<>25.00 OR reward_persen=0)");
    $conn->query("UPDATE bpjs_margin_settings SET threshold_persen=20.00, reward_persen=25.00 WHERE kelas='Kelas 3' AND (threshold_persen<>20.00 OR reward_persen=0)");

    $conn->query("CREATE TABLE IF NOT EXISTS bpjs_margin_details (
        id INT AUTO_INCREMENT PRIMARY KEY,
        upload_id INT NOT NULL,
        sumber_sheet VARCHAR(80) NULL,
        no_urut INT NULL,
        tgl_masuk VARCHAR(30) NULL,
        tgl_keluar VARCHAR(30) NULL,
        nama_pasien VARCHAR(180) NULL,
        no_rm VARCHAR(80) NULL,
        no_registrasi VARCHAR(100) NULL,
        no_sep VARCHAR(120) NULL,
        kelas_raw VARCHAR(120) NULL,
        kelas_norm ENUM('Kelas 1','Kelas 2','Kelas 3') NULL,
        nama_dpjp VARCHAR(180) NULL,
        diagnosis TEXT NULL,
        inacbg VARCHAR(80) NULL,
        deskripsi_inacbg TEXT NULL,
        tarif_inacbg DECIMAL(18,2) DEFAULT 0,
        tarif_naik_kelas DECIMAL(18,2) DEFAULT 0,
        klaim_bpjs DECIMAL(18,2) DEFAULT 0,
        billing_rs DECIMAL(18,2) DEFAULT 0,
        jasa_rs DECIMAL(18,2) DEFAULT 0,
        persen_jasa_rs DECIMAL(12,6) DEFAULT 0,
        threshold_margin DECIMAL(12,6) DEFAULT 0,
        minimal_jasa_rs DECIMAL(18,2) DEFAULT 0,
        reward_threshold DECIMAL(12,6) DEFAULT 0,
        maksimal_jasa_rs DECIMAL(18,2) DEFAULT 0,
        selisih_margin DECIMAL(18,2) DEFAULT 0,
        status_margin ENUM('SURPLUS','MINUS','AMAN') NULL,
        nominal_surplus DECIMAL(18,2) DEFAULT 0,
        nominal_minus DECIMAL(18,2) DEFAULT 0,
        bagian_rs DECIMAL(18,2) DEFAULT 0,
        bagian_dpjp DECIMAL(18,2) DEFAULT 0,
        jasa_dokter_awal DECIMAL(18,2) DEFAULT 0,
        potongan_minus_aktif DECIMAL(18,2) DEFAULT 0,
        tambahan_reward_dpjp DECIMAL(18,2) DEFAULT 0,
        jasa_dokter_final DECIMAL(18,2) DEFAULT 0,
        penyebab_minus TEXT NULL,
        rekomendasi TEXT NULL,
        is_minus_excluded TINYINT(1) NOT NULL DEFAULT 0,
        minus_exclude_note TEXT NULL,
        minus_excluded_by VARCHAR(150) NULL,
        minus_excluded_at DATETIME NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
        INDEX idx_upload (upload_id),
        INDEX idx_dpjp (nama_dpjp),
        INDEX idx_status (status_margin),
        CONSTRAINT fk_bpjs_margin_upload FOREIGN KEY (upload_id) REFERENCES bpjs_margin_uploads(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    // Migrasi aman untuk instalasi lama.
    bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details MODIFY status_margin ENUM('SURPLUS','MINUS','AMAN') NULL");
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'diagnosis')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN diagnosis TEXT NULL AFTER nama_dpjp");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'inacbg')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN inacbg VARCHAR(80) NULL AFTER diagnosis");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'deskripsi_inacbg')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN deskripsi_inacbg TEXT NULL AFTER inacbg");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'reward_threshold')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN reward_threshold DECIMAL(12,6) DEFAULT 0 AFTER minimal_jasa_rs");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'maksimal_jasa_rs')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN maksimal_jasa_rs DECIMAL(18,2) DEFAULT 0 AFTER reward_threshold");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'is_minus_excluded')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN is_minus_excluded TINYINT(1) NOT NULL DEFAULT 0 AFTER rekomendasi");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'minus_exclude_note')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN minus_exclude_note TEXT NULL AFTER is_minus_excluded");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'minus_excluded_by')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN minus_excluded_by VARCHAR(150) NULL AFTER minus_exclude_note");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'minus_excluded_at')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN minus_excluded_at DATETIME NULL AFTER minus_excluded_by");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'jasa_dokter_awal')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN jasa_dokter_awal DECIMAL(18,2) DEFAULT 0 AFTER bagian_dpjp");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'potongan_minus_aktif')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN potongan_minus_aktif DECIMAL(18,2) DEFAULT 0 AFTER jasa_dokter_awal");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'tambahan_reward_dpjp')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN tambahan_reward_dpjp DECIMAL(18,2) DEFAULT 0 AFTER potongan_minus_aktif");
    }
    if (!bpjs_column_exists($conn, 'bpjs_margin_details', 'jasa_dokter_final')) {
        bpjs_safe_query($conn, "ALTER TABLE bpjs_margin_details ADD COLUMN jasa_dokter_final DECIMAL(18,2) DEFAULT 0 AFTER tambahan_reward_dpjp");
    }
}

function bpjs_thresholds(mysqli $conn): array
{
    // min = punishment/batas minimal; max = reward/batas maksimal.
    $out = [
        'Kelas 1' => ['min' => 0.35, 'max' => 0.40],
        'Kelas 2' => ['min' => 0.25, 'max' => 0.35],
        'Kelas 3' => ['min' => 0.20, 'max' => 0.25],
    ];
    $res = $conn->query("SELECT kelas, threshold_persen, reward_persen FROM bpjs_margin_settings");
    if ($res) {
        while ($r = $res->fetch_assoc()) {
            $kelas = (string)$r['kelas'];
            $out[$kelas] = [
                'min' => ((float)$r['threshold_persen']) / 100,
                'max' => ((float)$r['reward_persen']) / 100,
            ];
        }
    }
    return $out;
}

function bpjs_normalize_header($s): string
{
    $s = strtolower(trim((string)$s));
    // Penting: jangan hilangkan tanda persen begitu saja.
    // Header "% Jasa RS" harus menjadi "persen jasa rs", bukan "jasa rs",
    // agar tidak menimpa kolom nominal "Jasa RS".
    $s = str_replace(['%', '％'], ' persen ', $s);
    $s = str_replace(['.', '/', '-', '_', '(', ')', "\n", "\r"], ' ', $s);
    $s = preg_replace('/\s+/', ' ', $s);
    return trim($s);
}
function bpjs_num($v): float
{
    if (is_numeric($v)) return (float)$v;
    $s = trim((string)$v);
    if ($s === '') return 0.0;
    $s = str_replace(["'", 'Rp', 'rp', 'IDR', 'idr', ' '], '', $s);
    if (strpos($s, ',') !== false && strpos($s, '.') !== false) {
        $s = str_replace('.', '', $s);
        $s = str_replace(',', '.', $s);
    } elseif (strpos($s, ',') !== false) {
        $s = str_replace(',', '.', $s);
    }
    $s = preg_replace('/[^0-9\.\-]/', '', $s);
    return is_numeric($s) ? (float)$s : 0.0;
}
function bpjs_norm_kelas($raw): string
{
    $s = strtolower((string)$raw);
    if (strpos($s, 'kelas 1') !== false || preg_match('/\bkls\s*1\b|\bk1\b/', $s)) return 'Kelas 1';
    if (strpos($s, 'kelas 2') !== false || preg_match('/\bkls\s*2\b|\bk2\b/', $s)) return 'Kelas 2';
    if (strpos($s, 'kelas 3') !== false || preg_match('/\bkls\s*3\b|\bk3\b/', $s)) return 'Kelas 3';
    return 'Kelas 1';
}
function bpjs_is_vip_row($kelasRaw, string $sheetName = ''): bool
{
    $s = strtolower((string)$kelasRaw . ' ' . $sheetName);
    return strpos($s, 'vip') !== false || strpos($s, 'vvip') !== false || strpos($s, 'eksekutif') !== false;
}
function bpjs_pick(array $row, array $map, array $names, $default = '')
{
    foreach ($names as $n) {
        $k = bpjs_normalize_header($n);
        if (isset($map[$k])) return $row[$map[$k]] ?? $default;
    }
    return $default;
}

function bpjs_col_name(int $n): string
{
    $s = '';
    while ($n > 0) { $m = ($n - 1) % 26; $s = chr(65 + $m) . $s; $n = intdiv($n - $m, 26); }
    return $s;
}
function bpjs_xml($s): string { return htmlspecialchars((string)$s, ENT_XML1 | ENT_COMPAT, 'UTF-8'); }

function bpjs_xlsx_children(SimpleXMLElement $node, string $name): array
{
    $out = [];
    foreach ($node->children() as $child) {
        if ($child->getName() === $name) $out[] = $child;
    }
    if ($out) return $out;
    foreach ($node->children('http://schemas.openxmlformats.org/spreadsheetml/2006/main') as $child) {
        if ($child->getName() === $name) $out[] = $child;
    }
    foreach ($node->children('http://schemas.openxmlformats.org/package/2006/relationships') as $child) {
        if ($child->getName() === $name) $out[] = $child;
    }
    return $out;
}
function bpjs_xlsx_first_child(SimpleXMLElement $node, string $name): ?SimpleXMLElement
{
    $arr = bpjs_xlsx_children($node, $name);
    return $arr[0] ?? null;
}
function bpjs_xlsx_all_t(SimpleXMLElement $node): string
{
    $txt = '';
    $nodes = $node->xpath('.//*[local-name()="t"]');
    if ($nodes) foreach ($nodes as $t) $txt .= (string)$t;
    return $txt;
}
function bpjs_read_xlsx(string $file): array
{
    if (!class_exists('ZipArchive')) {
        throw new RuntimeException('Ekstensi PHP zip/ZipArchive belum aktif. Aktifkan extension zip di cPanel/PHP Selector agar sistem bisa membaca file .xlsx.');
    }
    $zip = new ZipArchive();
    if ($zip->open($file) !== true) throw new RuntimeException('File XLSX tidak bisa dibuka. Pastikan file bukan .xls lama atau file rusak.');

    $shared = [];
    $sharedXml = $zip->getFromName('xl/sharedStrings.xml');
    if ($sharedXml !== false) {
        $sx = simplexml_load_string($sharedXml);
        if ($sx) {
            $items = $sx->xpath('//*[local-name()="si"]') ?: [];
            foreach ($items as $si) $shared[] = bpjs_xlsx_all_t($si);
        }
    }

    $workbookXml = $zip->getFromName('xl/workbook.xml');
    $relsXml = $zip->getFromName('xl/_rels/workbook.xml.rels');
    if ($workbookXml === false || $relsXml === false) {
        $zip->close();
        throw new RuntimeException('Struktur workbook XLSX tidak lengkap.');
    }
    $workbook = simplexml_load_string($workbookXml);
    $rels = simplexml_load_string($relsXml);
    if (!$workbook || !$rels) {
        $zip->close();
        throw new RuntimeException('Workbook XLSX tidak bisa dibaca.');
    }

    $relMap = [];
    $relNodes = $rels->xpath('//*[local-name()="Relationship"]') ?: [];
    foreach ($relNodes as $rel) {
        $relMap[(string)$rel['Id']] = (string)$rel['Target'];
    }

    $sheets = [];
    $sheetNodes = $workbook->xpath('//*[local-name()="sheet"]') ?: [];
    foreach ($sheetNodes as $sheet) {
        $attrs = $sheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
        $rid = (string)($attrs['id'] ?? '');
        if ($rid === '') $rid = (string)($sheet['r:id'] ?? '');
        $name = (string)$sheet['name'];
        $target = $relMap[$rid] ?? '';
        if ($target === '') continue;

        if (strpos($target, '/xl/') === 0) $path = ltrim($target, '/');
        elseif (strpos($target, 'xl/') === 0) $path = $target;
        else $path = 'xl/' . ltrim($target, '/');
        $path = str_replace('xl//', 'xl/', $path);

        $xml = $zip->getFromName($path);
        if ($xml === false) continue;
        $sx = simplexml_load_string($xml);
        if (!$sx) continue;

        $rows = [];
        $rowNodes = $sx->xpath('//*[local-name()="sheetData"]/*[local-name()="row"]') ?: [];
        foreach ($rowNodes as $rowNode) {
            $row = [];
            $cellNodes = $rowNode->xpath('./*[local-name()="c"]') ?: [];
            foreach ($cellNodes as $c) {
                $ref = (string)$c['r'];
                preg_match('/([A-Z]+)/', $ref, $m);
                $letters = $m[1] ?? 'A';
                $idx = 0;
                for ($i=0; $i<strlen($letters); $i++) $idx = $idx * 26 + (ord($letters[$i]) - 64);
                $idx--;

                $type = (string)$c['t'];
                $val = '';
                $vNodes = $c->xpath('./*[local-name()="v"]');
                if ($type === 's') {
                    $v = $vNodes && isset($vNodes[0]) ? (int)((string)$vNodes[0]) : -1;
                    $val = $shared[$v] ?? '';
                } elseif ($type === 'inlineStr') {
                    $val = bpjs_xlsx_all_t($c);
                } else {
                    $val = $vNodes && isset($vNodes[0]) ? (string)$vNodes[0] : '';
                }
                $row[$idx] = $val;
            }
            if ($row) {
                ksort($row);
                $rows[] = $row;
            }
        }
        $sheets[$name] = $rows;
    }
    $zip->close();
    return $sheets;
}

function bpjs_header_value(array $row, int $idx): string
{
    return bpjs_normalize_header($row[$idx] ?? '');
}
function bpjs_find_col(array $map, array $aliases): ?int
{
    foreach ($aliases as $alias) {
        $a = bpjs_normalize_header($alias);
        if (isset($map[$a])) return $map[$a];
    }
    foreach ($map as $h => $idx) {
        foreach ($aliases as $alias) {
            $a = bpjs_normalize_header($alias);
            if ($a !== '' && (strpos($h, $a) !== false || strpos($a, $h) !== false)) return $idx;
        }
    }
    return null;
}
function bpjs_pick2(array $row, array $map, array $names, $default = '')
{
    $idx = bpjs_find_col($map, $names);
    return $idx === null ? $default : ($row[$idx] ?? $default);
}

function bpjs_build_rows_from_xlsx(string $file, array $thresholds): array
{
    $sheets = bpjs_read_xlsx($file);
    $rowsOut = [];
    $seen = [];

    foreach ($sheets as $sheetName => $rows) {
        if (count($rows) < 2) continue;

        $headerRow = null; $headerIdx = null; $bestScore = -1;
        foreach ($rows as $i => $r) {
            if ($i > 30) break;
            $mapTmp = [];
            foreach ($r as $idx => $h) {
                $nh = bpjs_normalize_header($h);
                if ($nh !== '' && !isset($mapTmp[$nh])) $mapTmp[$nh] = $idx;
            }
            $score = 0;
            if (bpjs_find_col($mapTmp, ['Nama','Nama Pasien']) !== null) $score++;
            if (bpjs_find_col($mapTmp, ['Kelas BPJS','Kelas','Hak Kelas']) !== null) $score++;
            if (bpjs_find_col($mapTmp, ['Nama DPJP','DPJP','Dokter']) !== null) $score++;
            if (bpjs_find_col($mapTmp, ['Tarif INACBG','Tarif INA CBG','Klaim BPJS','Tarif Klaim']) !== null) $score++;
            if (bpjs_find_col($mapTmp, ['Jasa RS','Jasa Rumah Sakit']) !== null) $score++;
            if ($score > $bestScore) { $bestScore = $score; $headerRow = $r; $headerIdx = $i; }
            if ($score >= 4) break;
        }
        if (!$headerRow || $bestScore < 4) continue;

        $map = [];
        foreach ($headerRow as $idx => $h) {
            $nh = bpjs_normalize_header($h);
            if ($nh !== '' && !isset($map[$nh])) $map[$nh] = $idx;
        }

        for ($i = $headerIdx + 1; $i < count($rows); $i++) {
            $r = $rows[$i];
            $nama = trim((string)bpjs_pick2($r, $map, ['Nama','Nama Pasien']));
            $dpjp = trim((string)bpjs_pick2($r, $map, ['Nama DPJP','DPJP','Dokter','Dokter DPJP']));
            if ($nama === '' || $dpjp === '') continue;

            $noReg = trim((string)bpjs_pick2($r, $map, ['No Registrasi','No. Registrasi','Registrasi','Register']));
            $noSep = trim((string)bpjs_pick2($r, $map, ['No SEP','No. SEP','SEP']));
            $noRm = trim((string)bpjs_pick2($r, $map, ['No RM','No. RM','RM','Nomor RM']));
            $key = $noSep ?: ($noReg ?: ($noRm . '|' . $nama . '|' . $sheetName));
            if ($key && isset($seen[$key])) continue;
            $seen[$key] = true;

            $tarif = bpjs_num(bpjs_pick2($r, $map, ['Tarif INACBG','Tarif INA CBG','Tarif INA-CBG','Klaim BPJS','Tarif Klaim']));
            $naik = bpjs_num(bpjs_pick2($r, $map, ['Tarif Naik Kelas','Naik Kelas','Tambahan Naik Kelas']));
            $klaim = $tarif + $naik;
            $jasaInput = bpjs_num(bpjs_pick2($r, $map, ['Jasa RS','Jasa Rumah Sakit']));
            $persenInput = bpjs_num(bpjs_pick2($r, $map, ['% Jasa RS','Persen Jasa RS','Persentase Jasa RS']));

            // Kolom Jasa RS harus dibaca sebagai NOMINAL sesuai Excel.
            // Jika file lama/parser lama telanjur membaca kolom % Jasa RS sebagai Jasa RS
            // misal 39,17 atau -208,18, barulah angka kecil ini dikonversi menjadi nominal.
            // Nominal kecil <1000 secara operasional tidak realistis untuk jasa tindakan operasi BPJS,
            // sehingga aman dianggap sebagai persentase.
            if ($klaim > 0 && $jasaInput != 0 && abs($jasaInput) <= 1000) {
                $jasaPersen = $jasaInput / 100;
                $jasa = $klaim * $jasaPersen;
            } else {
                $jasa = $jasaInput;
                $jasaPersen = $persenInput != 0 ? ($persenInput / 100) : ($klaim > 0 ? ($jasa / $klaim) : 0);
            }
            $jasaDokterAwal = bpjs_num(bpjs_pick2($r, $map, ['Honor Dokter','Jasa Dokter','Jasa DPJP','Jasa Operator','Honor Operator','Operator','Dokter Operator']));
            if ($klaim <= 0 && $jasa == 0) continue;

            $kelasRaw = (string)bpjs_pick2($r, $map, ['Kelas BPJS','Kelas','Hak Kelas']);
            if (bpjs_is_vip_row($kelasRaw, (string)$sheetName)) continue; // VIP/VVIP dieksklusi sesuai kebijakan terbaru.
            $kelas = bpjs_norm_kelas($kelasRaw);
            $rule = $thresholds[$kelas] ?? ['min' => 0.20, 'max' => 0.25];
            $thrMin = (float)$rule['min'];
            $thrMax = (float)$rule['max'];
            $minimal = $klaim * $thrMin;
            $maksimal = $klaim * $thrMax;

            // Perhitungan terbaru:
            // Reward/SURPLUS hanya bila Jasa RS di atas jasa maksimal kelas.
            // Punishment/MINUS bila Jasa RS di bawah jasa minimal kelas.
            if ($jasa > $maksimal + 0.01) {
                $status = 'SURPLUS';
                $surplus = $jasa - $maksimal;
                $minus = 0;
                $selisih = $surplus;
            } elseif ($jasa < $minimal - 0.01) {
                $status = 'MINUS';
                $surplus = 0;
                $minus = $minimal - $jasa; // disimpan positif agar mudah direkap.
                $selisih = -$minus;
            } else {
                $status = 'AMAN';
                $surplus = 0;
                $minus = 0;
                $selisih = 0;
            }

            $potonganMinusAktif = $minus;
            $tambahanRewardDpjp = $surplus * 0.5;
            $jasaDokterFinal = $jasaDokterAwal - $potonganMinusAktif + $tambahanRewardDpjp;

            $rowsOut[] = [
                'sumber_sheet' => $sheetName,
                'no_urut' => (int)bpjs_num(bpjs_pick2($r, $map, ['No','No.','Nomor'])),
                'tgl_masuk' => (string)bpjs_pick2($r, $map, ['Tgl Masuk','Tanggal Masuk']),
                'tgl_keluar' => (string)bpjs_pick2($r, $map, ['Tgl Keluar','Tanggal Keluar']),
                'nama_pasien' => $nama,
                'no_rm' => $noRm,
                'no_registrasi' => $noReg,
                'no_sep' => $noSep,
                'kelas_raw' => $kelasRaw,
                'kelas_norm' => $kelas,
                'nama_dpjp' => $dpjp,
                'diagnosis' => (string)bpjs_pick2($r, $map, ['Diagnosis','Diagnosa','Diagnosis Utama','Diagnosa Utama','Diagnosa Primer','Diagnosis Primer']),
                'inacbg' => (string)bpjs_pick2($r, $map, ['INACBG','INACBGs','INA CBG','INA CBGs','INA-CBG','INA-CBGs','Kode INACBG','Kode INA-CBG']),
                'deskripsi_inacbg' => (string)bpjs_pick2($r, $map, ['Deskripsi INACBG','Deskripsi INACBGs','Deskripsi INA CBG','Deskripsi INA CBGs','Deskripsi INA-CBG','Deskripsi INA-CBGs','Uraian INACBG','Uraian INA-CBG']),
                'tarif_inacbg' => $tarif,
                'tarif_naik_kelas' => $naik,
                'klaim_bpjs' => $klaim,
                'billing_rs' => bpjs_num(bpjs_pick2($r, $map, ['Billing RS','Billing'])),
                'jasa_rs' => $jasa,
                'persen_jasa_rs' => $jasaPersen,
                'threshold_margin' => $thrMin,
                'minimal_jasa_rs' => $minimal,
                'reward_threshold' => $thrMax,
                'maksimal_jasa_rs' => $maksimal,
                'selisih_margin' => $selisih,
                'status_margin' => $status,
                'nominal_surplus' => $surplus,
                'nominal_minus' => $minus,
                'bagian_rs' => $surplus * 0.5,
                'bagian_dpjp' => $surplus * 0.5,
                'jasa_dokter_awal' => $jasaDokterAwal,
                'potongan_minus_aktif' => $potonganMinusAktif,
                'tambahan_reward_dpjp' => $tambahanRewardDpjp,
                'jasa_dokter_final' => $jasaDokterFinal,
            ];
        }
    }
    return $rowsOut;
}

function bpjs_insert_upload(mysqli $conn, array $dataRows, string $judul, string $bulan, int $tahun, string $stored, string $orig): int
{
    $uid = bpjs_current_user_id(); $uname = bpjs_current_name(); $total = count($dataRows);
    $stmt = $conn->prepare("INSERT INTO bpjs_margin_uploads (judul, periode_bulan, periode_tahun, file_name, original_file_name, total_rows, uploaded_by, uploaded_by_name) VALUES (?,?,?,?,?,?,?,?)");
    $stmt->bind_param('ssisssis', $judul, $bulan, $tahun, $stored, $orig, $total, $uid, $uname);
    $stmt->execute(); $uploadId = (int)$stmt->insert_id; $stmt->close();

    $sql = "INSERT INTO bpjs_margin_details
    (upload_id,sumber_sheet,no_urut,tgl_masuk,tgl_keluar,nama_pasien,no_rm,no_registrasi,no_sep,kelas_raw,kelas_norm,nama_dpjp,diagnosis,inacbg,deskripsi_inacbg,tarif_inacbg,tarif_naik_kelas,klaim_bpjs,billing_rs,jasa_rs,persen_jasa_rs,threshold_margin,minimal_jasa_rs,reward_threshold,maksimal_jasa_rs,selisih_margin,status_margin,nominal_surplus,nominal_minus,bagian_rs,bagian_dpjp,jasa_dokter_awal,potongan_minus_aktif,tambahan_reward_dpjp,jasa_dokter_final)
    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
    $stmt = $conn->prepare($sql);
    foreach ($dataRows as $r) {
        $stmt->bind_param('isissssssssssssdddddddddddsdddddddd',
            $uploadId, $r['sumber_sheet'], $r['no_urut'], $r['tgl_masuk'], $r['tgl_keluar'], $r['nama_pasien'], $r['no_rm'], $r['no_registrasi'], $r['no_sep'], $r['kelas_raw'], $r['kelas_norm'], $r['nama_dpjp'], $r['diagnosis'], $r['inacbg'], $r['deskripsi_inacbg'], $r['tarif_inacbg'], $r['tarif_naik_kelas'], $r['klaim_bpjs'], $r['billing_rs'], $r['jasa_rs'], $r['persen_jasa_rs'], $r['threshold_margin'], $r['minimal_jasa_rs'], $r['reward_threshold'], $r['maksimal_jasa_rs'], $r['selisih_margin'], $r['status_margin'], $r['nominal_surplus'], $r['nominal_minus'], $r['bagian_rs'], $r['bagian_dpjp'], $r['jasa_dokter_awal'], $r['potongan_minus_aktif'], $r['tambahan_reward_dpjp'], $r['jasa_dokter_final']
        );
        $stmt->execute();
    }
    $stmt->close();
    return $uploadId;
}

function bpjs_uploads(mysqli $conn): array
{
    $rows = [];
    $res = $conn->query("SELECT * FROM bpjs_margin_uploads ORDER BY id DESC LIMIT 50");
    if ($res) while ($r = $res->fetch_assoc()) $rows[] = $r;
    return $rows;
}
function bpjs_selected_upload(mysqli $conn): ?array
{
    $id = (int)($_GET['upload_id'] ?? 0);
    if ($id <= 0) {
        $res = $conn->query("SELECT * FROM bpjs_margin_uploads ORDER BY id DESC LIMIT 1");
        return $res ? $res->fetch_assoc() : null;
    }
    $stmt = $conn->prepare("SELECT * FROM bpjs_margin_uploads WHERE id=?");
    $stmt->bind_param('i', $id); $stmt->execute();
    $r = $stmt->get_result()->fetch_assoc(); $stmt->close(); return $r ?: null;
}
function bpjs_recalculate_upload(mysqli $conn, int $uploadId): void
{
    if ($uploadId <= 0) return;

    // Koreksi upload lama: jika Jasa RS masih terbaca 31/39/41 atau -208,18,
    // itu adalah persen yang dulu salah terambil dari kolom % Jasa RS, bukan nominal.
    // Setelah dikonversi, rekap dokter/kelas otomatis memakai nominal Jasa RS real.
    $id = (int)$uploadId;
    bpjs_safe_query($conn, "UPDATE bpjs_margin_details
        SET
            persen_jasa_rs = CASE
                WHEN klaim_bpjs > 0 AND jasa_rs <> 0 AND ABS(jasa_rs) <= 1000 THEN jasa_rs / 100
                WHEN klaim_bpjs > 0 THEN jasa_rs / klaim_bpjs
                ELSE 0
            END,
            jasa_rs = CASE
                WHEN klaim_bpjs > 0 AND jasa_rs <> 0 AND ABS(jasa_rs) <= 1000 THEN ROUND(klaim_bpjs * (jasa_rs / 100), 2)
                ELSE jasa_rs
            END
        WHERE upload_id = $id");

    bpjs_safe_query($conn, "UPDATE bpjs_margin_details
        SET
            nominal_surplus = CASE WHEN jasa_rs > maksimal_jasa_rs THEN jasa_rs - maksimal_jasa_rs ELSE 0 END,
            nominal_minus = CASE WHEN jasa_rs < minimal_jasa_rs THEN minimal_jasa_rs - jasa_rs ELSE 0 END,
            bagian_rs = CASE WHEN jasa_rs > maksimal_jasa_rs THEN (jasa_rs - maksimal_jasa_rs) * 0.5 ELSE 0 END,
            bagian_dpjp = CASE WHEN jasa_rs > maksimal_jasa_rs THEN (jasa_rs - maksimal_jasa_rs) * 0.5 ELSE 0 END,
            tambahan_reward_dpjp = CASE WHEN jasa_rs > maksimal_jasa_rs THEN (jasa_rs - maksimal_jasa_rs) * 0.5 ELSE 0 END,
            status_margin = CASE
                WHEN jasa_rs > maksimal_jasa_rs THEN 'SURPLUS'
                WHEN jasa_rs < minimal_jasa_rs THEN 'MINUS'
                ELSE 'AMAN'
            END,
            selisih_margin = CASE
                WHEN jasa_rs > maksimal_jasa_rs THEN jasa_rs - maksimal_jasa_rs
                WHEN jasa_rs < minimal_jasa_rs THEN -(minimal_jasa_rs - jasa_rs)
                ELSE 0
            END
        WHERE upload_id = $id");

    bpjs_safe_query($conn, "UPDATE bpjs_margin_details
        SET
            potongan_minus_aktif = CASE
                WHEN status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0 THEN nominal_minus
                ELSE 0
            END,
            jasa_dokter_final = jasa_dokter_awal
                - CASE WHEN status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0 THEN nominal_minus ELSE 0 END
                + CASE WHEN status_margin='SURPLUS' THEN bagian_dpjp ELSE 0 END
        WHERE upload_id = $id");
}

function bpjs_summary(mysqli $conn, int $uploadId): array
{
    $def = ['total_kasus'=>0,'total_klaim'=>0,'total_jasa'=>0,'minimal'=>0,'maksimal'=>0,'surplus_kasus'=>0,'minus_kasus'=>0,'aman_kasus'=>0,'excluded_minus_kasus'=>0,'total_surplus'=>0,'total_minus_raw'=>0,'total_minus_excluded'=>0,'total_minus'=>0,'net_reward'=>0,'bagian_rs'=>0,'bagian_dpjp'=>0,'total_jasa_dokter_awal'=>0,'total_potongan_minus_aktif'=>0,'total_tambahan_reward_dpjp'=>0,'total_jasa_dokter_final'=>0];
    if ($uploadId <= 0) return $def;
    $effMinus = "CASE WHEN status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1 THEN 0 ELSE nominal_minus END";
    $res = $conn->query("SELECT COUNT(*) total_kasus,
        COALESCE(SUM(klaim_bpjs),0) total_klaim,
        COALESCE(SUM(jasa_rs),0) total_jasa,
        COALESCE(SUM(minimal_jasa_rs),0) minimal,
        COALESCE(SUM(maksimal_jasa_rs),0) maksimal,
        SUM(status_margin='SURPLUS') surplus_kasus,
        SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0) minus_kasus,
        SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1) excluded_minus_kasus,
        SUM(status_margin='AMAN') aman_kasus,
        COALESCE(SUM(nominal_surplus),0) total_surplus,
        COALESCE(SUM(nominal_minus),0) total_minus_raw,
        COALESCE(SUM(CASE WHEN status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1 THEN nominal_minus ELSE 0 END),0) total_minus_excluded,
        COALESCE(SUM($effMinus),0) total_minus,
        (COALESCE(SUM(nominal_surplus),0)-COALESCE(SUM($effMinus),0)) net_reward,
        COALESCE(SUM(bagian_rs),0) bagian_rs,
        COALESCE(SUM(bagian_dpjp),0) bagian_dpjp,
        COALESCE(SUM(jasa_dokter_awal),0) total_jasa_dokter_awal,
        COALESCE(SUM($effMinus),0) total_potongan_minus_aktif,
        COALESCE(SUM(bagian_dpjp),0) total_tambahan_reward_dpjp,
        COALESCE(SUM(jasa_dokter_awal - $effMinus + bagian_dpjp),0) total_jasa_dokter_final
        FROM bpjs_margin_details WHERE upload_id=".(int)$uploadId);
    return $res ? array_merge($def, $res->fetch_assoc() ?: []) : $def;
}
function bpjs_fetch_all(mysqli $conn, string $sql): array
{
    $rows=[]; $res=$conn->query($sql); if($res) while($r=$res->fetch_assoc()) $rows[]=$r; return $rows;
}
function bpjs_effective_minus_sql(): string
{
    return "CASE WHEN status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1 THEN 0 ELSE nominal_minus END";
}
function bpjs_active_minus_case_sql(): string
{
    return "(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0)";
}

function bpjs_write_simple_xlsx(array $sheets, string $path): void
{
    if (!class_exists('ZipArchive')) {
        throw new RuntimeException('Ekstensi PHP zip/ZipArchive belum aktif. Aktifkan extension zip di cPanel/PHP Selector agar sistem bisa export .xlsx.');
    }
    $zip = new ZipArchive();
    if ($zip->open($path, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) throw new RuntimeException('Gagal membuat XLSX.');
    $zip->addFromString('[Content_Types].xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>'.implode('', array_map(fn($i)=>'<Override PartName="/xl/worksheets/sheet'.$i.'.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>', range(1,count($sheets)))).'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>');
    $zip->addFromString('_rels/.rels', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/></Relationships>');
    $zip->addFromString('docProps/core.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:creator>RS BaliMed</dc:creator><cp:lastModifiedBy>RS BaliMed</cp:lastModifiedBy><dcterms:created xsi:type="dcterms:W3CDTF">'.date('c').'</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">'.date('c').'</dcterms:modified></cp:coreProperties>');
    $zip->addFromString('docProps/app.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>RS BaliMed BPJS Margin</Application></Properties>');
    $sheetXml = ''; $relsXml = '';
    $i=1;
    foreach ($sheets as $name => $rows) {
        $safeName = substr(str_replace(['&','<','>'], ' ', (string)$name), 0, 31);
        $sheetXml .= '<sheet name="'.bpjs_xml($safeName).'" sheetId="'.$i.'" r:id="rId'.$i.'"/>';
        $relsXml .= '<Relationship Id="rId'.$i.'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet'.$i.'.xml"/>';
        $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheetData>';
        foreach (array_values($rows) as $rIdx => $row) {
            $rn = $rIdx + 1; $xml .= '<row r="'.$rn.'">'; $cIdx=1;
            $style = 0;
            if ($rIdx === 0) $style = 1;
            if ((string)$name === 'Detail_Analisa' && $rIdx > 0) {
                $statusVal = strtoupper((string)($row[23] ?? ''));
                if ($statusVal === 'MINUS') $style = 2;
                if ($statusVal === 'SURPLUS') $style = 3;
            }
            $styleAttr = $style > 0 ? ' s="'.$style.'"' : '';
            foreach (array_values($row) as $val) {
                $cell = bpjs_col_name($cIdx).$rn;
                if (is_int($val) || is_float($val) || (is_numeric($val) && $val !== '' && !preg_match('/^0\d+/', (string)$val))) {
                    $xml .= '<c r="'.$cell.'"'.$styleAttr.'><v>'.((float)$val).'</v></c>';
                } else {
                    $xml .= '<c r="'.$cell.'"'.$styleAttr.' t="inlineStr"><is><t>'.bpjs_xml((string)$val).'</t></is></c>';
                }
                $cIdx++;
            }
            $xml .= '</row>';
        }
        $xml .= '</sheetData></worksheet>';
        $zip->addFromString('xl/worksheets/sheet'.$i.'.xml', $xml);
        $i++;
    }
    $zip->addFromString('xl/workbook.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets>'.$sheetXml.'</sheets></workbook>');
    $zip->addFromString('xl/_rels/workbook.xml.rels', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'.$relsXml.'<Relationship Id="rId999" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>');
    $zip->addFromString('xl/styles.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="2"><font><sz val="11"/><name val="Calibri"/></font><font><b/><sz val="11"/><name val="Calibri"/><color rgb="FFFFFFFF"/></font></fonts><fills count="5"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FF1E293B"/><bgColor indexed="64"/></patternFill></fill><fill><patternFill patternType="solid"><fgColor rgb="FFFEE2E2"/><bgColor indexed="64"/></patternFill></fill><fill><patternFill patternType="solid"><fgColor rgb="FFDCFCE7"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="1"><border/></borders><cellStyleXfs count="1"><xf/></cellStyleXfs><cellXfs count="4"><xf xfId="0" fontId="0" fillId="0" borderId="0"/><xf xfId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1"/><xf xfId="0" fontId="0" fillId="3" borderId="0" applyFill="1"/><xf xfId="0" fontId="0" fillId="4" borderId="0" applyFill="1"/></cellXfs></styleSheet>');
    $zip->close();
}

function bpjs_export(mysqli $conn, int $uploadId): void
{
    $upload = bpjs_fetch_all($conn, "SELECT * FROM bpjs_margin_uploads WHERE id=".(int)$uploadId)[0] ?? null;
    if (!$upload) exit('Data upload tidak ditemukan.');
    $summary = bpjs_summary($conn, $uploadId);
    $detail = bpjs_fetch_all($conn, "SELECT * FROM bpjs_margin_details WHERE upload_id=".(int)$uploadId." ORDER BY FIELD(kelas_norm,'Kelas 1','Kelas 2','Kelas 3'), nama_dpjp, nama_pasien");
    $effMinus = bpjs_effective_minus_sql();
    $dokter = bpjs_fetch_all($conn, "SELECT nama_dpjp, COUNT(*) jumlah_kasus, SUM(status_margin='SURPLUS') kasus_surplus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0) kasus_minus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1) kasus_exclude, SUM(status_margin='AMAN') kasus_aman, SUM(klaim_bpjs) total_klaim, SUM(jasa_rs) total_jasa, SUM(minimal_jasa_rs) minimal, SUM(maksimal_jasa_rs) maksimal, SUM(nominal_surplus) total_surplus, SUM($effMinus) total_minus, (SUM(nominal_surplus)-SUM($effMinus)) net_margin, COALESCE(SUM(bagian_rs),0) bagian_rs, COALESCE(SUM(bagian_dpjp),0) bagian_dpjp, COALESCE(SUM(jasa_dokter_awal),0) total_jasa_dokter_awal, COALESCE(SUM($effMinus),0) potongan_minus_aktif, COALESCE(SUM(bagian_dpjp),0) tambahan_reward_dpjp, COALESCE(SUM(jasa_dokter_awal - $effMinus + bagian_dpjp),0) total_jasa_dokter_final, IFNULL(SUM(jasa_rs)/NULLIF(SUM(klaim_bpjs),0),0) rasio FROM bpjs_margin_details WHERE upload_id=".(int)$uploadId." GROUP BY nama_dpjp ORDER BY nama_dpjp");
    $kelas = bpjs_fetch_all($conn, "SELECT kelas_norm, AVG(threshold_margin) threshold, AVG(reward_threshold) reward_threshold, COUNT(*) jumlah_kasus, SUM(status_margin='SURPLUS') kasus_surplus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0) kasus_minus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1) kasus_exclude, SUM(status_margin='AMAN') kasus_aman, SUM(klaim_bpjs) total_klaim, SUM(jasa_rs) total_jasa, SUM(minimal_jasa_rs) minimal, SUM(maksimal_jasa_rs) maksimal, SUM(nominal_surplus) total_surplus, SUM($effMinus) total_minus, (SUM(nominal_surplus)-SUM($effMinus)) net_margin, COALESCE(SUM(bagian_rs),0) bagian_rs, COALESCE(SUM(bagian_dpjp),0) bagian_dpjp, COALESCE(SUM(jasa_dokter_awal),0) total_jasa_dokter_awal, COALESCE(SUM($effMinus),0) potongan_minus_aktif, COALESCE(SUM(bagian_dpjp),0) tambahan_reward_dpjp, COALESCE(SUM(jasa_dokter_awal - $effMinus + bagian_dpjp),0) total_jasa_dokter_final, IFNULL(SUM(jasa_rs)/NULLIF(SUM(klaim_bpjs),0),0) rasio FROM bpjs_margin_details WHERE upload_id=".(int)$uploadId." GROUP BY kelas_norm ORDER BY FIELD(kelas_norm,'Kelas 1','Kelas 2','Kelas 3')");
    $excluded = bpjs_fetch_all($conn, "SELECT * FROM bpjs_margin_details WHERE upload_id=".(int)$uploadId." AND status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1 ORDER BY nama_dpjp, nama_pasien");

    $sheets = [];
    $sheets['Dashboard'] = [
        ['LAPORAN REWARD & PUNISHMENT JASA RS - TINDAKAN OPERASI BPJS'],
        ['Judul', $upload['judul'], 'Periode', trim(($upload['periode_bulan'] ?? '').' '.($upload['periode_tahun'] ?? ''))],
        [],
        ['Total Kasus', (int)$summary['total_kasus'], 'Total Klaim BPJS', (float)$summary['total_klaim']],
        ['Total Jasa RS', (float)$summary['total_jasa'], 'Minimal Jasa RS', (float)$summary['minimal']],
        ['Maksimal/Reward Jasa RS', (float)$summary['maksimal'], 'Kasus Aman', (int)$summary['aman_kasus']],
        ['Kasus Reward', (int)$summary['surplus_kasus'], 'Kasus Minus Aktif', (int)$summary['minus_kasus']],
        ['Total Reward', (float)$summary['total_surplus'], 'Total Minus Aktif', (float)$summary['total_minus']],
        ['Minus Diexclude', (float)$summary['total_minus_excluded'], 'Kasus Exclude Minus', (int)$summary['excluded_minus_kasus']],
        ['Net Reward Setelah Minus', (float)$summary['net_reward'], 'Reward DPJP dihitung 50% dari selisih surplus per kasus', ''],
        ['Bagian RS 50%', (float)$summary['bagian_rs'], 'Bagian DPJP/Operator 50%', (float)$summary['bagian_dpjp']],
    ];
    $sheets['Detail_Analisa'] = [[ 'Sumber','No','Tgl Masuk','Tgl Keluar','Nama Pasien','No RM','No Registrasi','No SEP','Kelas','Nama DPJP','Diagnosis','INACBG','Deskripsi INACBG','Tarif INACBG','Tarif Naik Kelas','Klaim BPJS','Billing RS','Jasa RS','% Jasa RS','Batas Minus','Minimal Jasa RS','Batas Reward','Maksimal Jasa RS','Status','Reward/Surplus','Minus Raw','Minus Aktif','Minus Exclude','Selisih Net Aktif','Bagian RS 50%','Bagian DPJP/Operator 50%','Jasa Dokter Awal','Potongan Minus Aktif','Tambahan Reward DPJP','Jasa Dokter Final','Penyebab Minus','Rekomendasi','Status Exclude','Keterangan Exclude' ]];
    foreach ($detail as $r) {
        $ex = (int)($r['is_minus_excluded'] ?? 0);
        $aktif = $ex ? 0 : (float)$r['nominal_minus'];
        $sheets['Detail_Analisa'][] = [$r['sumber_sheet'], $r['no_urut'], $r['tgl_masuk'], $r['tgl_keluar'], $r['nama_pasien'], $r['no_rm'], $r['no_registrasi'], $r['no_sep'], $r['kelas_norm'], $r['nama_dpjp'], $r['diagnosis'], $r['inacbg'], $r['deskripsi_inacbg'], (float)$r['tarif_inacbg'], (float)$r['tarif_naik_kelas'], (float)$r['klaim_bpjs'], (float)$r['billing_rs'], (float)$r['jasa_rs'], (float)$r['persen_jasa_rs'], (float)$r['threshold_margin'], (float)$r['minimal_jasa_rs'], (float)$r['reward_threshold'], (float)$r['maksimal_jasa_rs'], $r['status_margin'], (float)$r['nominal_surplus'], (float)$r['nominal_minus'], $aktif, $ex?(float)$r['nominal_minus']:0, ((float)$r['nominal_surplus']-$aktif), (float)$r['bagian_rs'], (float)$r['bagian_dpjp'], (float)($r['jasa_dokter_awal'] ?? 0), (float)$aktif, (float)($r['bagian_dpjp'] ?? 0), ((float)($r['jasa_dokter_awal'] ?? 0) - (float)$aktif + (float)($r['bagian_dpjp'] ?? 0)), $r['penyebab_minus'], $r['rekomendasi'], $ex?'EXCLUDED':'INCLUDED', $r['minus_exclude_note']];
    }
    $sheets['Rekap_Dokter'] = [[ 'Nama DPJP','Jumlah Kasus','Kasus Reward','Kasus Minus Aktif','Kasus Minus Exclude','Kasus Aman','Total Klaim BPJS','Total Jasa RS','Minimal Jasa RS','Maksimal Jasa RS','Total Reward','Total Minus Aktif','Net Reward-Minus','Bagian RS 50% dari Surplus','Bagian DPJP/Operator 50% dari Surplus','Jasa Dokter Awal','Potongan Minus Aktif','Tambahan Reward DPJP','Jasa Dokter Final','Rasio Jasa RS' ]];
    foreach ($dokter as $r) $sheets['Rekap_Dokter'][] = [$r['nama_dpjp'], (int)$r['jumlah_kasus'], (int)$r['kasus_surplus'], (int)$r['kasus_minus'], (int)($r['kasus_exclude'] ?? 0), (int)$r['kasus_aman'], (float)$r['total_klaim'], (float)$r['total_jasa'], (float)$r['minimal'], (float)$r['maksimal'], (float)$r['total_surplus'], (float)$r['total_minus'], (float)$r['net_margin'], (float)$r['bagian_rs'], (float)$r['bagian_dpjp'], (float)($r['total_jasa_dokter_awal'] ?? 0), (float)($r['potongan_minus_aktif'] ?? 0), (float)($r['tambahan_reward_dpjp'] ?? 0), (float)($r['total_jasa_dokter_final'] ?? 0), (float)$r['rasio']];
    $sheets['Rekap_Kelas'] = [[ 'Kelas','Batas Minus','Batas Reward','Jumlah Kasus','Kasus Reward','Kasus Minus Aktif','Kasus Minus Exclude','Kasus Aman','Total Klaim BPJS','Total Jasa RS','Minimal Jasa RS','Maksimal Jasa RS','Total Reward','Total Minus Aktif','Net Reward-Minus','Bagian RS 50%','Bagian DPJP/Operator 50%','Jasa Dokter Awal','Potongan Minus Aktif','Tambahan Reward DPJP','Jasa Dokter Final','Rasio Jasa RS' ]];
    foreach ($kelas as $r) $sheets['Rekap_Kelas'][] = [$r['kelas_norm'], (float)$r['threshold'], (float)$r['reward_threshold'], (int)$r['jumlah_kasus'], (int)$r['kasus_surplus'], (int)$r['kasus_minus'], (int)($r['kasus_exclude'] ?? 0), (int)$r['kasus_aman'], (float)$r['total_klaim'], (float)$r['total_jasa'], (float)$r['minimal'], (float)$r['maksimal'], (float)$r['total_surplus'], (float)$r['total_minus'], (float)$r['net_margin'], (float)$r['bagian_rs'], (float)$r['bagian_dpjp'], (float)($r['total_jasa_dokter_awal'] ?? 0), (float)($r['potongan_minus_aktif'] ?? 0), (float)($r['tambahan_reward_dpjp'] ?? 0), (float)($r['total_jasa_dokter_final'] ?? 0), (float)$r['rasio']];
    $sheets['Exclude_Minus'] = [[ 'Nama DPJP','Nama Pasien','No RM','Kelas','Klaim BPJS','Jasa RS','Minus Diexclude','Penyebab Minus','Rekomendasi','Keterangan Exclude','Oleh','Tanggal Exclude' ]];
    foreach ($excluded as $r) $sheets['Exclude_Minus'][] = [$r['nama_dpjp'], $r['nama_pasien'], $r['no_rm'], $r['kelas_norm'], (float)$r['klaim_bpjs'], (float)$r['jasa_rs'], (float)$r['nominal_minus'], $r['penyebab_minus'], $r['rekomendasi'], $r['minus_exclude_note'], $r['minus_excluded_by'], $r['minus_excluded_at']];
    $sheets['Asumsi'] = [
        ['Parameter','Nilai','Keterangan'],
        ['Reward Kelas 1',0.40,'Reward bila % Jasa RS > 40% dari klaim INA-CBGs'],
        ['Reward Kelas 2',0.35,'Reward bila % Jasa RS > 35% dari klaim INA-CBGs'],
        ['Reward Kelas 3',0.25,'Reward bila % Jasa RS > 25% dari klaim INA-CBGs'],
        ['Punishment Kelas 1',0.35,'Minus bila % Jasa RS < 35% dari klaim INA-CBGs'],
        ['Punishment Kelas 2',0.25,'Minus bila % Jasa RS < 25% dari klaim INA-CBGs'],
        ['Punishment Kelas 3',0.20,'Minus bila % Jasa RS < 20% dari klaim INA-CBGs'],
        ['VIP/VVIP','Eksklusi','Data VIP/VVIP tidak dihitung dalam analisa'],
        ['Pembagian reward',0.50,'Net reward per dokter = total reward - total minus aktif. Minus yang diexclude tidak mengurangi net dokter. Jika net positif, dibagi 50% operator/DPJP dan 50% RS']
    ];
    $tmp = tempnam(sys_get_temp_dir(), 'bpjs_margin_').'.xlsx';
    bpjs_write_simple_xlsx($sheets, $tmp);
    while (ob_get_level()) ob_end_clean();
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename="Analisa_Margin_Operasi_BPJS_'.$uploadId.'.xlsx"');
    header('Content-Length: '.filesize($tmp));
    readfile($tmp); @unlink($tmp); exit;
}

bpjs_install_tables($conn);

if (isset($_GET['action']) && $_GET['action'] === 'export') {
    bpjs_export($conn, (int)($_GET['upload_id'] ?? 0));
}

$alert = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = (string)($_POST['action'] ?? '');
    try {
        if ($action === 'upload_excel') {
            if (!isset($_FILES['excel_file']) || $_FILES['excel_file']['error'] !== UPLOAD_ERR_OK) throw new RuntimeException('File Excel belum dipilih / gagal upload.');
            $ext = strtolower(pathinfo($_FILES['excel_file']['name'], PATHINFO_EXTENSION));
            if ($ext !== 'xlsx') throw new RuntimeException('Format yang didukung saat ini adalah .xlsx. Simpan Excel sebagai .xlsx lalu upload ulang.');
            $dir = __DIR__ . '/../../uploads/bpjs_margin_operasi'; if (!is_dir($dir)) mkdir($dir, 0775, true);
            $stored = 'bpjs_margin_'.date('Ymd_His').'_'.bin2hex(random_bytes(3)).'.xlsx';
            $dest = $dir . '/' . $stored;
            if (!move_uploaded_file($_FILES['excel_file']['tmp_name'], $dest)) throw new RuntimeException('Gagal menyimpan file upload.');
            $rows = bpjs_build_rows_from_xlsx($dest, bpjs_thresholds($conn));
            if (!$rows) throw new RuntimeException('Tidak ada baris valid terbaca. Pastikan header Excel berisi Nama Pasien/Nama, Kelas BPJS, Nama DPJP/Dokter, Tarif INACBG/Klaim BPJS, Jasa RS, dan bila tersedia Honor Dokter/Jasa Dokter. VIP/VVIP otomatis dieksklusi.');
            $judul = trim((string)($_POST['judul'] ?? 'Analisa Margin Operasi BPJS')) ?: 'Analisa Margin Operasi BPJS';
            $bulan = trim((string)($_POST['periode_bulan'] ?? ''));
            $tahun = (int)($_POST['periode_tahun'] ?? date('Y'));
            $uploadId = bpjs_insert_upload($conn, $rows, $judul, $bulan, $tahun, $stored, (string)$_FILES['excel_file']['name']);
            echo "<script>location.href='index.php?module=bpjs_margin_operasi&upload_id=".(int)$uploadId."&ok=upload';</script>"; return;
        }
        if ($action === 'save_minus_note') {
            $id = (int)($_POST['detail_id'] ?? 0);
            $penyebab = trim((string)($_POST['penyebab_minus'] ?? ''));
            $rekom = trim((string)($_POST['rekomendasi'] ?? ''));
            $stmt = $conn->prepare("UPDATE bpjs_margin_details SET penyebab_minus=?, rekomendasi=? WHERE id=?");
            $stmt->bind_param('ssi', $penyebab, $rekom, $id); $stmt->execute(); $stmt->close();
            echo "<script>location.href='index.php?module=bpjs_margin_operasi&upload_id=".(int)($_POST['upload_id'] ?? 0)."&ok=note';</script>"; return;
        }
        if ($action === 'toggle_minus_exclusion') {
            $id = (int)($_POST['detail_id'] ?? 0);
            $uploadPost = (int)($_POST['upload_id'] ?? 0);
            $exclude = (int)($_POST['exclude'] ?? 0) === 1 ? 1 : 0;
            $userName = bpjs_current_name();
            if ($exclude) {
                $stmt = $conn->prepare("UPDATE bpjs_margin_details SET is_minus_excluded=1, potongan_minus_aktif=0, jasa_dokter_final=(jasa_dokter_awal + tambahan_reward_dpjp), minus_exclude_note=COALESCE(NULLIF(penyebab_minus,''), rekomendasi, 'Minus diexclude setelah review petugas'), minus_excluded_by=?, minus_excluded_at=NOW() WHERE id=? AND status_margin='MINUS' AND COALESCE(penyebab_minus,'')<>''");
                $stmt->bind_param('si', $userName, $id); $stmt->execute(); $stmt->close();
            } else {
                $stmt = $conn->prepare("UPDATE bpjs_margin_details SET is_minus_excluded=0, potongan_minus_aktif=nominal_minus, jasa_dokter_final=(jasa_dokter_awal - nominal_minus + tambahan_reward_dpjp), minus_exclude_note=NULL, minus_excluded_by=NULL, minus_excluded_at=NULL WHERE id=?");
                $stmt->bind_param('i', $id); $stmt->execute(); $stmt->close();
            }
            echo "<script>location.href='index.php?module=bpjs_margin_operasi&upload_id=".$uploadPost."&ok=exclude';</script>"; return;
        }
        if ($action === 'save_settings') {
            foreach (['Kelas 1','Kelas 2','Kelas 3'] as $kelas) {
                $minVal = (float)($_POST['threshold'][$kelas] ?? 0);
                $maxVal = (float)($_POST['reward'][$kelas] ?? 0);
                if ($minVal <= 0 || $maxVal <= 0) continue;
                $stmt = $conn->prepare("UPDATE bpjs_margin_settings SET threshold_persen=?, reward_persen=? WHERE kelas=?");
                $stmt->bind_param('dds', $minVal, $maxVal, $kelas); $stmt->execute(); $stmt->close();
            }
            $alert = ['type'=>'success','msg'=>'Setting punishment dan reward berhasil disimpan. Berlaku untuk upload berikutnya.'];
        }
        if ($action === 'delete_upload') {
            $id = (int)($_POST['upload_id'] ?? 0);
            $stmt = $conn->prepare("DELETE FROM bpjs_margin_uploads WHERE id=?"); $stmt->bind_param('i',$id); $stmt->execute(); $stmt->close();
            echo "<script>location.href='index.php?module=bpjs_margin_operasi&ok=delete';</script>"; return;
        }
    } catch (Throwable $e) { $alert = ['type'=>'error','msg'=>$e->getMessage()]; }
}

$uploads = bpjs_uploads($conn);
$selected = bpjs_selected_upload($conn);
$uploadId = $selected ? (int)$selected['id'] : 0;
if ($uploadId) { bpjs_recalculate_upload($conn, $uploadId); }
$summary = bpjs_summary($conn, $uploadId);
$dokterFilter = trim((string)($_GET['dokter_filter'] ?? ''));
$kelasFilter = trim((string)($_GET['kelas_filter'] ?? ''));
$allowedKelasFilter = ['Kelas 1','Kelas 2','Kelas 3'];
if (!in_array($kelasFilter, $allowedKelasFilter, true)) { $kelasFilter = ''; }
$filterParts = [];
if ($uploadId && $dokterFilter !== '') {
    $filterParts[] = "nama_dpjp='" . $conn->real_escape_string($dokterFilter) . "'";
}
if ($uploadId && $kelasFilter !== '') {
    $filterParts[] = "kelas_norm='" . $conn->real_escape_string($kelasFilter) . "'";
}
$filterSql = $filterParts ? (' AND ' . implode(' AND ', $filterParts)) : '';
$doctorOptions = $uploadId ? bpjs_fetch_all($conn, "SELECT DISTINCT nama_dpjp FROM bpjs_margin_details WHERE upload_id=$uploadId AND nama_dpjp<>'' ORDER BY nama_dpjp") : [];
$kelasOptions = $uploadId ? bpjs_fetch_all($conn, "SELECT kelas_norm, COUNT(*) jumlah FROM bpjs_margin_details WHERE upload_id=$uploadId AND kelas_norm<>'' GROUP BY kelas_norm ORDER BY FIELD(kelas_norm,'Kelas 1','Kelas 2','Kelas 3')") : [];
$detailRows = $uploadId ? bpjs_fetch_all($conn, "SELECT * FROM bpjs_margin_details WHERE upload_id=$uploadId $filterSql ORDER BY FIELD(kelas_norm,'Kelas 1','Kelas 2','Kelas 3'), FIELD(status_margin,'MINUS','SURPLUS','AMAN'), COALESCE(is_minus_excluded,0), nama_dpjp, nama_pasien LIMIT 500") : [];
$effMinusPage = bpjs_effective_minus_sql();
$dokterRows = $uploadId ? bpjs_fetch_all($conn, "SELECT nama_dpjp, COUNT(*) jumlah_kasus, SUM(status_margin='SURPLUS') kasus_surplus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0) kasus_minus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1) kasus_exclude, SUM(status_margin='AMAN') kasus_aman, SUM(klaim_bpjs) total_klaim, SUM(jasa_rs) total_jasa, SUM(minimal_jasa_rs) minimal, SUM(maksimal_jasa_rs) maksimal, SUM(nominal_surplus) total_surplus, SUM($effMinusPage) total_minus, (SUM(nominal_surplus)-SUM($effMinusPage)) net_margin, COALESCE(SUM(bagian_rs),0) bagian_rs, COALESCE(SUM(bagian_dpjp),0) bagian_dpjp, COALESCE(SUM(jasa_dokter_awal),0) total_jasa_dokter_awal, COALESCE(SUM($effMinusPage),0) potongan_minus_aktif, COALESCE(SUM(bagian_dpjp),0) tambahan_reward_dpjp, COALESCE(SUM(jasa_dokter_awal - $effMinusPage + bagian_dpjp),0) total_jasa_dokter_final, IFNULL(SUM(jasa_rs)/NULLIF(SUM(klaim_bpjs),0),0) rasio FROM bpjs_margin_details WHERE upload_id=$uploadId GROUP BY nama_dpjp ORDER BY net_margin ASC") : [];
$kelasRows = $uploadId ? bpjs_fetch_all($conn, "SELECT kelas_norm, COUNT(*) jumlah_kasus, SUM(status_margin='SURPLUS') kasus_surplus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=0) kasus_minus, SUM(status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1) kasus_exclude, SUM(status_margin='AMAN') kasus_aman, SUM(klaim_bpjs) total_klaim, SUM(jasa_rs) total_jasa, AVG(threshold_margin) threshold, AVG(reward_threshold) reward_threshold, SUM(minimal_jasa_rs) minimal, SUM(maksimal_jasa_rs) maksimal, SUM(nominal_surplus) total_surplus, SUM($effMinusPage) total_minus, (SUM(nominal_surplus)-SUM($effMinusPage)) net_margin, COALESCE(SUM(bagian_rs),0) bagian_rs, COALESCE(SUM(bagian_dpjp),0) bagian_dpjp, COALESCE(SUM(jasa_dokter_awal),0) total_jasa_dokter_awal, COALESCE(SUM($effMinusPage),0) potongan_minus_aktif, COALESCE(SUM(bagian_dpjp),0) tambahan_reward_dpjp, COALESCE(SUM(jasa_dokter_awal - $effMinusPage + bagian_dpjp),0) total_jasa_dokter_final, IFNULL(SUM(jasa_rs)/NULLIF(SUM(klaim_bpjs),0),0) rasio FROM bpjs_margin_details WHERE upload_id=$uploadId GROUP BY kelas_norm ORDER BY FIELD(kelas_norm,'Kelas 1','Kelas 2','Kelas 3')") : [];
$excludedRows = $uploadId ? bpjs_fetch_all($conn, "SELECT * FROM bpjs_margin_details WHERE upload_id=$uploadId AND status_margin='MINUS' AND COALESCE(is_minus_excluded,0)=1 ORDER BY nama_dpjp, nama_pasien") : [];
$settings = bpjs_thresholds($conn);
?>

<div class="space-y-6">
    <div class="bg-gradient-to-r from-slate-900 via-blue-900 to-indigo-900 rounded-2xl p-6 text-white shadow-xl">
        <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
            <div>
                <p class="text-blue-200 text-sm font-semibold uppercase tracking-wider">Evaluasi Keuangan BPJS</p>
                <h1 class="text-2xl md:text-3xl font-bold mt-1">Analisa Margin Operasi BPJS</h1>
                <p class="text-slate-200 mt-2">Upload Excel tindakan operasi, sistem otomatis menghitung reward/punishment jasa RS, eksklusi VIP, pembagian reward RS–DPJP, dan rekap jasa dokter final per dokter.</p>
            </div>
            <?php if ($uploadId): ?>
            <a href="index.php?module=bpjs_margin_operasi&action=export&upload_id=<?= $uploadId ?>" class="inline-flex items-center justify-center px-5 py-3 rounded-xl bg-emerald-500 hover:bg-emerald-600 text-white font-semibold shadow-lg">
                <i class="fas fa-file-excel mr-2"></i> Export Excel
            </a>
            <?php endif; ?>
        </div>
    </div>

    <?php if ($alert): ?>
        <div class="p-4 rounded-xl <?= $alert['type']==='error'?'bg-red-50 text-red-700 border border-red-200':'bg-emerald-50 text-emerald-700 border border-emerald-200' ?>"><?= bpjs_e($alert['msg']) ?></div>
    <?php endif; ?>
    <?php if (isset($_GET['ok'])): ?>
        <div class="p-4 rounded-xl bg-emerald-50 text-emerald-700 border border-emerald-200">Proses berhasil disimpan.</div>
    <?php endif; ?>

    <div class="space-y-6">
        <details class="bg-white rounded-2xl shadow border border-slate-100 overflow-hidden">
            <summary class="cursor-pointer list-none p-5 flex items-center justify-between gap-3 bg-white hover:bg-slate-50">
                <div>
                    <h2 class="font-bold text-lg text-slate-800"><i class="fas fa-sliders-h text-blue-600 mr-2"></i>Upload Excel & Setting Threshold</h2>
                    <p class="text-sm text-slate-500">Klik untuk buka/tutup form upload dan setting. Default ditutup agar tabel detail lebih luas.</p>
                </div>
                <span class="px-4 py-2 rounded-xl bg-blue-600 text-white font-bold text-sm"><i class="fas fa-chevron-down mr-1"></i> Buka Panel</span>
            </summary>
            <div class="p-5 border-t grid grid-cols-1 lg:grid-cols-2 gap-6">
                <div>
                    <h2 class="font-bold text-lg text-slate-800 mb-4"><i class="fas fa-upload text-blue-600 mr-2"></i>Upload Excel Baru</h2>
                    <form method="post" enctype="multipart/form-data" class="space-y-3">
                <input type="hidden" name="action" value="upload_excel">
                <div><label class="text-sm font-semibold text-slate-600">Judul Analisa</label><input name="judul" class="w-full mt-1 rounded-xl border-slate-300 focus:ring-blue-500" value="Analisa Margin Operasi BPJS"></div>
                <div class="grid grid-cols-2 gap-3">
                    <div><label class="text-sm font-semibold text-slate-600">Bulan</label><input name="periode_bulan" class="w-full mt-1 rounded-xl border-slate-300" placeholder="Januari"></div>
                    <div><label class="text-sm font-semibold text-slate-600">Tahun</label><input name="periode_tahun" type="number" class="w-full mt-1 rounded-xl border-slate-300" value="<?= date('Y') ?>"></div>
                </div>
                <div><label class="text-sm font-semibold text-slate-600">File Excel .xlsx</label><input name="excel_file" type="file" accept=".xlsx" required class="w-full mt-1 rounded-xl border border-slate-300 p-2"></div>
                <button class="w-full py-3 rounded-xl bg-blue-600 hover:bg-blue-700 text-white font-bold"><i class="fas fa-magic mr-2"></i>Upload & Analisa</button>
                    </form>
                </div>
                <div class="border-t lg:border-t-0 lg:border-l pt-4 lg:pt-0 lg:pl-6">
                <h3 class="font-bold text-slate-700 mb-2">Setting Threshold</h3>
                <form method="post" class="space-y-2">
                    <input type="hidden" name="action" value="save_settings">
                    <div class="grid grid-cols-3 gap-2 text-xs font-bold text-slate-500"><span>Kelas</span><span class="text-right">Minus &lt;</span><span class="text-right">Reward &gt;</span></div>
                    <?php foreach ($settings as $k=>$v): ?><div class="grid grid-cols-3 gap-2 items-center"><span class="text-sm font-semibold"><?= bpjs_e($k) ?></span><input name="threshold[<?= bpjs_e($k) ?>]" type="number" step="0.01" value="<?= number_format($v['min']*100,2,'.','') ?>" class="rounded-lg border-slate-300 text-right"><input name="reward[<?= bpjs_e($k) ?>]" type="number" step="0.01" value="<?= number_format($v['max']*100,2,'.','') ?>" class="rounded-lg border-slate-300 text-right"></div><?php endforeach; ?>
                    <p class="text-xs text-slate-500">VIP/VVIP otomatis dieksklusi dari analisa.</p>
                    <button class="w-full mt-2 py-2 rounded-lg bg-slate-800 text-white font-semibold">Simpan Setting</button>
                </form>
            </div>
            </div>
        </details>

        <div class="space-y-6">
            <div class="bg-white rounded-2xl shadow p-5 border border-slate-100">
                <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 mb-4">
                    <h2 class="font-bold text-lg text-slate-800"><i class="fas fa-folder-open text-indigo-600 mr-2"></i>Data Analisa</h2>
                    <form method="get" class="flex gap-2">
                        <input type="hidden" name="module" value="bpjs_margin_operasi">
                        <select name="upload_id" class="rounded-xl border-slate-300" onchange="this.form.submit()">
                            <?php foreach ($uploads as $u): ?><option value="<?= (int)$u['id'] ?>" <?= $uploadId===(int)$u['id']?'selected':'' ?>>#<?= (int)$u['id'] ?> - <?= bpjs_e($u['judul']) ?> (<?= (int)$u['total_rows'] ?>)</option><?php endforeach; ?>
                        </select>
                    </form>
                </div>
                <?php if ($selected): ?>
                    <p class="text-sm text-slate-500 mb-4">File: <b><?= bpjs_e($selected['original_file_name']) ?></b> | Periode: <?= bpjs_e(($selected['periode_bulan'] ?? '').' '.($selected['periode_tahun'] ?? '')) ?> | Upload: <?= bpjs_e($selected['created_at']) ?></p>
                    <div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
                        <div class="rounded-2xl p-4 bg-blue-50"><p class="text-sm text-blue-700">Total Kasus</p><p class="text-2xl font-bold text-blue-900"><?= (int)$summary['total_kasus'] ?></p></div>
                        <div class="rounded-2xl p-4 bg-emerald-50"><p class="text-sm text-emerald-700">Reward/Surplus</p><p class="text-2xl font-bold text-emerald-900"><?= (int)$summary['surplus_kasus'] ?></p><p class="text-xs"><?= bpjs_money($summary['total_surplus']) ?></p></div>
                        <div class="rounded-2xl p-4 bg-red-50"><p class="text-sm text-red-700">Punishment/Minus Aktif</p><p class="text-2xl font-bold text-red-900"><?= (int)$summary['minus_kasus'] ?></p><p class="text-xs"><?= bpjs_money($summary['total_minus']) ?> aktif</p><p class="text-[11px] text-red-500">Exclude: <?= (int)$summary['excluded_minus_kasus'] ?> kasus / <?= bpjs_money($summary['total_minus_excluded']) ?></p></div>
                        <div class="rounded-2xl p-4 bg-violet-50"><p class="text-sm text-violet-700">Jasa Dokter Final</p><p class="text-xl font-bold text-violet-900"><?= bpjs_money($summary['total_jasa_dokter_final']) ?></p><p class="text-[11px]">Awal: <?= bpjs_money($summary['total_jasa_dokter_awal']) ?> | -Minus: <?= bpjs_money($summary['total_potongan_minus_aktif']) ?> | +Reward: <?= bpjs_money($summary['total_tambahan_reward_dpjp']) ?></p></div>
                    </div>
                <?php else: ?>
                    <div class="text-center py-10 text-slate-500">Belum ada data. Silakan upload Excel terlebih dahulu.</div>
                <?php endif; ?>
            </div>

            <?php if ($uploadId): ?>
            <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
                <div class="bg-white rounded-2xl shadow p-5 border border-slate-100 overflow-x-auto">
                    <h3 class="font-bold text-slate-800 mb-3">Rekap Per Kelas</h3>
                    <table class="min-w-full text-xs"><thead><tr class="bg-slate-100"><th class="p-2 text-left">Kelas</th><th class="p-2">Kasus</th><th class="p-2 text-right">Jasa RS Real</th><th class="p-2 text-right">Min Standar</th><th class="p-2 text-right">Reward Standar</th><th class="p-2">Reward</th><th class="p-2">Minus Aktif</th><th class="p-2">Exclude</th><th class="p-2 text-right">Net</th></tr></thead><tbody>
                    <?php foreach($kelasRows as $r): ?><tr class="border-b"><td class="p-2 font-semibold"><?= bpjs_e($r['kelas_norm']) ?></td><td class="p-2 text-center"><?= (int)$r['jumlah_kasus'] ?></td><td class="p-2 text-right"><?= bpjs_money($r['total_jasa']) ?></td><td class="p-2 text-right"><?= bpjs_money($r['minimal']) ?></td><td class="p-2 text-right"><?= bpjs_money($r['maksimal']) ?></td><td class="p-2 text-center text-emerald-700"><?= (int)$r['kasus_surplus'] ?><br><span class="text-[11px]"><?= bpjs_money($r['total_surplus']) ?></span></td><td class="p-2 text-center text-red-700"><?= (int)$r['kasus_minus'] ?><br><span class="text-[11px]"><?= bpjs_money($r['total_minus']) ?></span></td><td class="p-2 text-center text-slate-500"><?= (int)($r['kasus_exclude'] ?? 0) ?></td><td class="p-2 text-right font-semibold <?= ((float)$r['net_margin']<0)?'text-red-700':'text-emerald-700' ?>"><?= bpjs_money($r['net_margin']) ?></td></tr><?php endforeach; ?>
                    </tbody></table>
                </div>
                <div class="bg-white rounded-2xl shadow p-5 border border-slate-100 overflow-x-auto">
                    <h3 class="font-bold text-slate-800 mb-3">Rekap Per Dokter / DPJP</h3>
                    <table class="min-w-full text-sm"><thead><tr class="bg-slate-100"><th class="p-2 text-left">DPJP</th><th class="p-2">Kasus</th><th class="p-2">Reward</th><th class="p-2">Minus Aktif</th><th class="p-2">Exclude</th><th class="p-2 text-right">Net Reward-Minus</th><th class="p-2 text-right">Jasa Dokter Awal</th><th class="p-2 text-right">Jasa Dokter Final</th></tr></thead><tbody>
                    <?php foreach($dokterRows as $r): ?><tr class="border-b"><td class="p-2 font-semibold"><?= bpjs_e($r['nama_dpjp']) ?></td><td class="p-2 text-center"><?= (int)$r['jumlah_kasus'] ?></td><td class="p-2 text-center text-emerald-700"><?= (int)$r['kasus_surplus'] ?></td><td class="p-2 text-center text-red-700"><?= (int)$r['kasus_minus'] ?></td><td class="p-2 text-center text-slate-500"><?= (int)($r['kasus_exclude'] ?? 0) ?></td><td class="p-2 text-right font-semibold <?= ((float)$r['net_margin']<0)?'text-red-700':'text-emerald-700' ?>"><?= bpjs_money($r['net_margin']) ?></td><td class="p-2 text-right"><?= bpjs_money($r['total_jasa_dokter_awal'] ?? 0) ?></td><td class="p-2 text-right font-bold text-violet-700"><?= bpjs_money($r['total_jasa_dokter_final'] ?? 0) ?><br><span class="text-[11px] text-slate-500">-<?= bpjs_money($r['potongan_minus_aktif'] ?? 0) ?> +<?= bpjs_money($r['tambahan_reward_dpjp'] ?? 0) ?></span></td></tr><?php endforeach; ?>
                    </tbody></table>
                </div>
            </div>

            <?php if (!empty($excludedRows)): ?>
            <div class="bg-white rounded-2xl shadow border border-slate-100 overflow-hidden">
                <div class="p-5 border-b"><h3 class="font-bold text-slate-800">Tabel Exclude Minus</h3><p class="text-sm text-slate-500">Minus yang sudah diexclude tidak mengurangi net reward dokter. Keterangan diambil dari penyebab minus/rekomendasi yang diisi petugas.</p></div>
                <div class="overflow-x-auto"><table class="min-w-full text-xs"><thead class="bg-slate-800 text-white"><tr><th class="p-3 text-left">DPJP</th><th class="p-3 text-left">Pasien</th><th class="p-3 text-right">Minus Exclude</th><th class="p-3 text-left">Keterangan</th><th class="p-3">Aksi</th></tr></thead><tbody>
                <?php foreach($excludedRows as $ex): ?>
                    <tr class="border-b bg-slate-50"><td class="p-3 font-semibold"><?= bpjs_e($ex['nama_dpjp']) ?></td><td class="p-3"><?= bpjs_e($ex['nama_pasien']) ?><br><span class="text-slate-500"><?= bpjs_e($ex['no_rm']) ?></span></td><td class="p-3 text-right font-bold text-red-700"><?= bpjs_money($ex['nominal_minus']) ?></td><td class="p-3"><?= bpjs_e($ex['minus_exclude_note'] ?: $ex['penyebab_minus']) ?><br><span class="text-slate-500">Oleh: <?= bpjs_e($ex['minus_excluded_by']) ?> | <?= bpjs_e($ex['minus_excluded_at']) ?></span></td><td class="p-3 text-center"><form method="post"><input type="hidden" name="action" value="toggle_minus_exclusion"><input type="hidden" name="detail_id" value="<?= (int)$ex['id'] ?>"><input type="hidden" name="upload_id" value="<?= (int)$uploadId ?>"><input type="hidden" name="exclude" value="0"><button class="px-3 py-2 rounded-lg bg-slate-700 text-white font-semibold">Include Minus</button></form></td></tr>
                <?php endforeach; ?>
                </tbody></table></div>
            </div>
            <?php endif; ?>

            <div class="bg-white rounded-2xl shadow border border-slate-100 overflow-hidden">
                <div class="p-5 border-b flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3">
                    <div>
                        <h3 class="font-bold text-slate-800">Detail Analisa & Input Penyebab Minus / Dasar Exclude</h3>
                        <p class="text-xs text-slate-500 mt-1">Gunakan filter dokter dan kelas agar data detail tidak tercampur.</p>
                    </div>
                    <form method="get" class="flex flex-col sm:flex-row sm:items-center gap-2">
                        <input type="hidden" name="module" value="bpjs_margin_operasi">
                        <input type="hidden" name="upload_id" value="<?= (int)$uploadId ?>">
                        <select name="dokter_filter" class="rounded-xl border-slate-300 text-sm min-w-[240px]" onchange="this.form.submit()">
                            <option value="">Semua Dokter/DPJP</option>
                            <?php foreach($doctorOptions as $d): ?><option value="<?= bpjs_e($d['nama_dpjp']) ?>" <?= $dokterFilter===$d['nama_dpjp']?'selected':'' ?>><?= bpjs_e($d['nama_dpjp']) ?></option><?php endforeach; ?>
                        </select>
                        <select name="kelas_filter" class="rounded-xl border-slate-300 text-sm min-w-[140px]" onchange="this.form.submit()">
                            <option value="">Semua Kelas</option>
                            <?php foreach($kelasOptions as $k): ?><option value="<?= bpjs_e($k['kelas_norm']) ?>" <?= $kelasFilter===$k['kelas_norm']?'selected':'' ?>><?= bpjs_e($k['kelas_norm']) ?> (<?= (int)$k['jumlah'] ?>)</option><?php endforeach; ?>
                        </select>
                        <?php if($dokterFilter !== '' || $kelasFilter !== ''): ?>
                            <a href="index.php?module=bpjs_margin_operasi&upload_id=<?= (int)$uploadId ?>" class="px-3 py-2 rounded-xl bg-slate-100 hover:bg-slate-200 text-slate-700 text-sm font-semibold text-center">Reset</a>
                        <?php endif; ?>
                        <span class="text-xs text-slate-500 whitespace-nowrap">Maks. 500 baris</span>
                    </form>
                </div>
                <div class="overflow-x-auto">
                    <table class="min-w-full text-xs">
                        <thead class="bg-slate-900 text-white"><tr><th class="p-3 text-left">Pasien</th><th class="p-3 text-left">DPJP</th><th class="p-3 text-left">Diagnosis & INACBG</th><th class="p-3">Kelas</th><th class="p-3 text-right">Klaim</th><th class="p-3 text-right">Jasa RS Real</th><th class="p-3 text-right">Standar Jasa RS</th><th class="p-3">Margin</th><th class="p-3">Status</th><th class="p-3 text-right">Jasa Dokter Final</th><th class="p-3 text-left">Penyebab Minus</th><th class="p-3">Exclude</th><th class="p-3">Aksi</th></tr></thead>
                        <tbody>
                        <?php if(empty($detailRows)): ?>
                            <tr><td colspan="13" class="p-8 text-center text-slate-500">Tidak ada data untuk kombinasi filter dokter/kelas ini.</td></tr>
                        <?php endif; ?>
                        <?php foreach($detailRows as $r): $isMinus=$r['status_margin']==='MINUS'; $isSurplus=$r['status_margin']==='SURPLUS'; $isExcluded=((int)($r['is_minus_excluded'] ?? 0)===1); ?>
                            <tr class="border-b <?= $isExcluded?'bg-slate-100':($isMinus?'bg-red-50':($isSurplus?'bg-emerald-50/40':'bg-amber-50/40')) ?>">
                                <td class="p-3"><b><?= bpjs_e($r['nama_pasien']) ?></b><br><span class="text-slate-500"><?= bpjs_e($r['no_rm']) ?></span></td>
                                <td class="p-3"><?= bpjs_e($r['nama_dpjp']) ?></td>
                                <td class="p-3 min-w-[260px]"><b><?= bpjs_e($r['diagnosis'] ?: '-') ?></b><br><span class="text-slate-500">INACBG: <?= bpjs_e($r['inacbg'] ?: '-') ?></span><br><span class="text-slate-500"><?= bpjs_e($r['deskripsi_inacbg'] ?: '-') ?></span></td>
                                <td class="p-3 text-center"><?= bpjs_e($r['kelas_norm']) ?></td>
                                <td class="p-3 text-right"><?= bpjs_money($r['klaim_bpjs']) ?></td>
                                <td class="p-3 text-right"><b><?= bpjs_money($r['jasa_rs']) ?></b><br><span class="text-slate-500 text-[11px]"><?= bpjs_pct($r['persen_jasa_rs']) ?> dari klaim</span></td>
                                <td class="p-3 text-right"><span class="text-red-700 font-semibold">Min <?= bpjs_money($r['minimal_jasa_rs']) ?></span><br><span class="text-emerald-700 font-semibold">Reward <?= bpjs_money($r['maksimal_jasa_rs']) ?></span></td>
                                <td class="p-3 text-center"><?= bpjs_pct($r['persen_jasa_rs']) ?><br><span class="text-slate-500">Min <?= bpjs_pct($r['threshold_margin']) ?> | Reward &gt; <?= bpjs_pct($r['reward_threshold']) ?></span></td>
                                <td class="p-3 text-center"><span class="px-2 py-1 rounded-full font-bold <?= $isMinus?'bg-red-600 text-white':($isSurplus?'bg-emerald-600 text-white':'bg-amber-500 text-white') ?>"><?= bpjs_e($r['status_margin']) ?></span><?php if($isExcluded): ?><br><span class="px-2 py-1 rounded-full bg-slate-700 text-white text-[10px] font-bold">EXCLUDED</span><?php endif; ?><br><span class="<?= $isMinus?'text-red-700':($isSurplus?'text-emerald-700':'text-amber-700') ?> font-semibold"><?= bpjs_money($r['selisih_margin']) ?></span></td>
                                <td class="p-3 text-right"><b><?= bpjs_money(((float)($r['jasa_dokter_awal'] ?? 0)) - ($isExcluded ? 0 : (float)$r['nominal_minus']) + (float)$r['bagian_dpjp']) ?></b><br><span class="text-slate-500 text-[11px]">Awal <?= bpjs_money($r['jasa_dokter_awal'] ?? 0) ?><br>-Minus <?= bpjs_money($isExcluded ? 0 : $r['nominal_minus']) ?><br>+Reward <?= bpjs_money($r['bagian_dpjp']) ?></span></td>
                                <td class="p-3 min-w-[220px]"><?= $r['penyebab_minus'] ? bpjs_e($r['penyebab_minus']) : '<span class="text-slate-400">Belum diisi</span>' ?></td>
                                <td class="p-3 text-center">
                                    <?php if($isMinus && $r['penyebab_minus']): ?>
                                        <form method="post" onsubmit="return confirm('<?= $isExcluded ? 'Masukkan kembali minus ini ke rekap dokter?' : 'Exclude minus ini dari total minus dokter?' ?>');">
                                            <input type="hidden" name="action" value="toggle_minus_exclusion"><input type="hidden" name="detail_id" value="<?= (int)$r['id'] ?>"><input type="hidden" name="upload_id" value="<?= (int)$uploadId ?>"><input type="hidden" name="exclude" value="<?= $isExcluded?0:1 ?>">
                                            <button class="px-3 py-2 rounded-lg <?= $isExcluded?'bg-slate-700 hover:bg-slate-800':'bg-amber-500 hover:bg-amber-600' ?> text-white font-semibold"><?= $isExcluded?'Include Minus':'Exclude Minus' ?></button>
                                        </form>
                                    <?php elseif($isMinus): ?><span class="text-xs text-slate-400">Isi note dulu</span><?php else: ?><span class="text-slate-400">-</span><?php endif; ?>
                                </td>
                                <td class="p-3 text-center"><?php if($isMinus): ?><button type="button" onclick='openMinusModal(<?= json_encode(["id"=>(int)$r["id"],"upload_id"=>$uploadId,"pasien"=>$r["nama_pasien"],"dokter"=>$r["nama_dpjp"],"minus"=>bpjs_money($r["selisih_margin"]),"penyebab"=>$r["penyebab_minus"],"rekom"=>$r["rekomendasi"],"diagnosis"=>$r["diagnosis"],"inacbg"=>$r["inacbg"],"deskripsi"=>$r["deskripsi_inacbg"],"jasa_rs"=>bpjs_money($r["jasa_rs"]),"minimal"=>bpjs_money($r["minimal_jasa_rs"]),"reward"=>bpjs_money($r["maksimal_jasa_rs"])], JSON_HEX_APOS|JSON_HEX_QUOT) ?>)' class="px-3 py-2 rounded-lg bg-red-600 text-white font-semibold">Isi/Edit</button><?php else: ?><span class="text-slate-400">-</span><?php endif; ?></td>
                            </tr>
                        <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
            </div>
            <?php endif; ?>
        </div>
    </div>
</div>

<div id="minusModal" class="fixed inset-0 bg-black/50 hidden items-center justify-center z-50 p-4">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-2xl p-6">
        <div class="flex items-start justify-between mb-4"><div><h3 class="text-xl font-bold text-slate-900">Input Penyebab Minus / Dasar Exclude</h3><p id="modalInfo" class="text-sm text-slate-500"></p><div id="modalClinical" class="mt-3 rounded-xl bg-slate-50 border border-slate-200 p-3 text-sm text-slate-700 hidden"></div></div><button onclick="closeMinusModal()" class="text-slate-400 hover:text-red-600 text-2xl">&times;</button></div>
        <form method="post" class="space-y-4">
            <input type="hidden" name="action" value="save_minus_note"><input type="hidden" name="detail_id" id="detail_id"><input type="hidden" name="upload_id" id="upload_id">
            <div><label class="text-sm font-bold text-slate-700">Penyebab Minus</label><textarea name="penyebab_minus" id="penyebab_minus" rows="4" class="w-full mt-1 rounded-xl border-slate-300" placeholder="Contoh: tarif INA-CBG rendah, tindakan kompleks, bahan/alkes tinggi, lama rawat tinggi, komplikasi/penyulit klinis..."></textarea></div>
            <div><label class="text-sm font-bold text-slate-700">Rekomendasi / Tindak Lanjut</label><textarea name="rekomendasi" id="rekomendasi" rows="3" class="w-full mt-1 rounded-xl border-slate-300" placeholder="Contoh: evaluasi clinical pathway, audit coding, review komponen jasa, negosiasi pola pembagian..."></textarea></div>
            <div class="flex justify-end gap-2"><button type="button" onclick="closeMinusModal()" class="px-4 py-2 rounded-xl bg-slate-100">Batal</button><button class="px-5 py-2 rounded-xl bg-blue-600 text-white font-bold">Simpan</button></div>
        </form>
    </div>
</div>
<script>
function escapeHtml(str){ return String(str).replace(/[&<>"']/g, function(m){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'})[m]; }); }
function openMinusModal(data){
    document.getElementById('minusModal').classList.remove('hidden'); document.getElementById('minusModal').classList.add('flex');
    document.getElementById('detail_id').value=data.id; document.getElementById('upload_id').value=data.upload_id;
    document.getElementById('penyebab_minus').value=data.penyebab||''; document.getElementById('rekomendasi').value=data.rekom||'';
    document.getElementById('modalInfo').textContent = data.pasien + ' | ' + data.dokter + ' | Selisih: ' + data.minus;
    const clinical = document.getElementById('modalClinical');
    const diagnosis = data.diagnosis || '-';
    const inacbg = data.inacbg || '-';
    const deskripsi = data.deskripsi || '-';
    clinical.innerHTML = '<b>Diagnosis:</b> ' + escapeHtml(diagnosis) + '<br><b>INACBG:</b> ' + escapeHtml(inacbg) + '<br><b>Deskripsi INACBG:</b> ' + escapeHtml(deskripsi) + '<hr class="my-2"><b>Jasa RS Real:</b> ' + escapeHtml(data.jasa_rs || '-') + '<br><b>Minimal Jasa RS:</b> ' + escapeHtml(data.minimal || '-') + '<br><b>Reward Standar:</b> ' + escapeHtml(data.reward || '-');
    clinical.classList.remove('hidden');
}
function closeMinusModal(){ document.getElementById('minusModal').classList.add('hidden'); document.getElementById('minusModal').classList.remove('flex'); }
</script>
