<?php

require_once(ROOT_URL . '/includes/asset/asset_functions.php');
if (!function_exists('enrepReportDataFromRow')) {
    function enrepReportDataFromRow(array $row): array
    {
        $value = $row['reportdata'] ?? '';
        if (is_array($value)) {
            return $value;
        }
        if (!is_string($value) || trim($value) === '') {
            return [];
        }
        $decoded = json_decode($value, true);
        if (!is_array($decoded)) {
            return [];
        }
        return (isset($decoded['version'], $decoded['fields']) && is_array($decoded['fields']))
            ? $decoded['fields']
            : $decoded;
    }
}

$_SESSION['returnLanding'] = 'index.php?t=includes/master&p=linked.php&clientnumber=' . intval($_REQUEST['clientnumber'] ?? 0) . '&itemnumber=' . intval($_REQUEST['itemnumber'] ?? 0);

function rr_getSurveyorName(int $id): string
{
    $stmt = $GLOBALS['con']->prepare("SELECT `surname`,`forename` FROM `surveyor` WHERE `id`=?") or die(mysqli_error($GLOBALS['con']));
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $r = $stmt->get_result();
    $stmt->close();
    if (!$r || $r->num_rows === 0) return 'Unknown';
    $cd = $r->fetch_assoc();
    return trim(($cd['forename'] ?? '') . ' ' . ($cd['surname'] ?? ''));
}

$clientnumber = intval($_REQUEST['clientnumber'] ?? 0);
$seedItem = intval($_REQUEST['itemnumber'] ?? 0);

if ($clientnumber <= 0 || $seedItem <= 0) {
    echo '<div class="alert alert-danger">Missing clientnumber or itemnumber.</div>';
    exit;
}

/**
 * RapidRep allow-list:
 * Locking is now based on the LAST report row's reportitems.reptype for the item (not itemdetails.reptype).
 * The main table lock uses the full RapidRep allow-list plus tenant rapidAllow.php entries.
 * The initial-report dropdown filters default/core RapidRep types by selected master_formtypes,
 * then appends tenant rapidAllow.php entries from tenant dd_formtypes.
 */
$defaultRapidReptypes = ["500", "502", "503", "504", "506"];
$rapidAllowReptypes = [];

$rapidAllowFile = '../'.TENANT_URL . '/output/rapidAllow.php';
if (is_file($rapidAllowFile)) {
    $rapidAllow = [];
    $rapidAllowResult = include $rapidAllowFile;
    if (is_array($rapidAllowResult)) {
        $rapidAllow = $rapidAllowResult;
    }

    if (is_array($rapidAllow) && count($rapidAllow) > 0) {
        $rapidAllow = array_map('strval', $rapidAllow);
        $rapidAllow = array_filter($rapidAllow, fn($reptype) => preg_match('/^\d+$/', $reptype));
        $rapidAllowReptypes = array_values(array_unique($rapidAllow));
    }
}

$selectedMasterReptypes = [];
$selectedRes = mysqli_query($GLOBALS['con'], "SELECT `formnumber` FROM `master_formtypes` WHERE `toggle` = 1") or die(mysqli_error($GLOBALS['con']));
while ($selectedRow = mysqli_fetch_assoc($selectedRes)) {
    $selectedFormnumber = trim((string)($selectedRow['formnumber'] ?? ''));
    if ($selectedFormnumber !== '') {
        $selectedMasterReptypes[] = $selectedFormnumber;
    }
}
$selectedMasterReptypes = array_values(array_unique($selectedMasterReptypes));

$rapidLockReptypes = array_values(array_unique(array_merge($defaultRapidReptypes, $rapidAllowReptypes)));
$initialRapidReptypes = array_values(array_filter($defaultRapidReptypes, fn($reptype) => in_array($reptype, $selectedMasterReptypes, true)));

function rr_formtypeMeta(mysqli $db, array $formnumbers): array
{
    if (count($formnumbers) === 0) {
        return [];
    }

    $formnumbers = array_values(array_unique(array_map('strval', $formnumbers)));
    $placeholders = implode(',', array_fill(0, count($formnumbers), '?'));
    $stmt = $db->prepare("SELECT `formnumber`, `formtype`, `description`, `shortdesc` FROM `dd_formtypes` WHERE `formnumber` IN ($placeholders)") or die(mysqli_error($db));
    $types = str_repeat('s', count($formnumbers));
    $stmt->bind_param($types, ...$formnumbers);
    $stmt->execute();
    $rs = $stmt->get_result();
    $stmt->close();

    $byFormnumber = [];
    while ($rs && ($row = $rs->fetch_assoc())) {
        $id = trim((string)($row['formnumber'] ?? ''));
        if ($id === '') {
            continue;
        }
        $label = trim((string)($row['description'] ?? ''));
        if ($label === '') {
            $label = trim((string)($row['shortdesc'] ?? ''));
        }
        if ($label === '') {
            $label = 'Report type ' . $id;
        }
        $type = trim((string)($row['formtype'] ?? ''));
        $byFormnumber[$id] = [
            'id' => $id,
            'label' => $label,
            'type' => ($type !== '' ? $type : $id),
        ];
    }

    $meta = [];
    foreach ($formnumbers as $formnumber) {
        if (isset($byFormnumber[$formnumber])) {
            $meta[] = $byFormnumber[$formnumber];
        }
    }

    return $meta;
}

$allowedReptypesMeta = [];
if (isset($GLOBALS['master']) && $GLOBALS['master'] instanceof mysqli) {
    $allowedReptypesMeta = array_merge($allowedReptypesMeta, rr_formtypeMeta($GLOBALS['master'], $initialRapidReptypes));
}
$allowedReptypesMeta = array_merge($allowedReptypesMeta, rr_formtypeMeta($GLOBALS['con'], $rapidAllowReptypes));

$stmt = $GLOBALS['con']->prepare("SELECT `itemnumber`,`desc`,`linked`,`statuslive` FROM `itemdetails` WHERE `itemnumber`=? AND `clientnumber`=?") or die(mysqli_error($GLOBALS['con']));
$stmt->bind_param('ii', $seedItem, $clientnumber);
$stmt->execute();
$seedRes = $stmt->get_result();
$stmt->close();

if (!$seedRes || $seedRes->num_rows === 0) {
    echo '<div class="alert alert-danger">Seed item not found.</div>';
    exit;
}
$seedRow = $seedRes->fetch_assoc();

$linkedRaw = (string)($seedRow['linked'] ?? '');

$chainId = '0';
$chainDesc = '';
$chainItems = [];

if (preg_match('/^\s*(\d+)\s*:/', $linkedRaw, $m)) {
    $chainId = (string)$m[1];
}

$lb = strpos($linkedRaw, '[');
$rb = strrpos($linkedRaw, ']');
if ($lb !== false && $rb !== false && $rb > $lb) {
    $inside = substr($linkedRaw, $lb + 1, $rb - $lb - 1);
    if (preg_match_all('/\d+/', $inside, $mm)) {
        $chainItems = array_map('intval', $mm[0]);
    }
}

$posLastColon = strrpos($linkedRaw, ':');
if ($posLastColon !== false) {
    $tail = trim(substr($linkedRaw, $posLastColon + 1));
    $tail = trim($tail, " \t\n\r\0\x0B\"'");
    if ($tail !== '' && $tail !== '""') $chainDesc = $tail;
}

if (count($chainItems) === 0) $chainItems = [$seedItem];
$chainItems = array_values(array_unique(array_filter($chainItems, fn($x) => $x > 0)));

$chainTitleText = 'C' . ($chainId ?: '0') . ($chainDesc ? ': ' . $chainDesc : '');
$chainTitle = htmlspecialchars($chainTitleText, ENT_QUOTES, 'UTF-8');

$repRewind = '';
$storedCount = 0;
$storedEntry = null;

$c = mysqli_query($GLOBALS['con'], "SELECT * FROM `rapid_history` WHERE `clientnumber`='" . $clientnumber . "' AND `chain`='" . mysqli_real_escape_string($GLOBALS['con'], $chainId) . "' ORDER BY `date` DESC LIMIT 1");
if ($c && mysqli_num_rows($c) > 0) {
    $storedEntry = mysqli_fetch_assoc($c);
    $storedPayload = (string)($storedEntry['reps'] ?? '[]');

    $maybe = json_decode($storedPayload, true);
    if (is_array($maybe)) {
        if (count($maybe) > 0 && is_array($maybe[0])) $storedCount = count($maybe);
        else $storedCount = count($maybe);
    }

    if ($storedCount > 0) {
        $repRewind = '<a id="repidRewind" href="javascript:void(0)" onclick="repidRewind()" class="btn btn-info btn-sm"
            data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
            title="There are ' . $storedCount . ' reports stored for recovery. Stored on ' . date('d-m-Y', intval($storedEntry['date'])) . '">
            <i class="fad fa-history"></i> Report Rewind</a>';
    }
}

$itemPlaceholders = implode(',', array_fill(0, count($chainItems), '?'));

$sql = "
SELECT
  a.itemnumber, a.clientnumber, a.locnumber, a.subloc, a.`desc`, a.code, a.currdate, a.plantnumber, a.serialnumber,
  a.model, a.dateofmanf, a.manf, a.swl, a.duedate, a.itemnotes, a.lastReport, a.statuslive, a.reptype,
  b.locname, b.postcode

FROM itemdetails a
LEFT JOIN locations b
  ON (b.locnumber = a.locnumber AND b.clientnumber = a.clientnumber)

WHERE a.clientnumber = ?
  AND a.statuslive = 1
  AND a.itemnumber IN ($itemPlaceholders)
ORDER BY a.locnumber ASC, a.itemnumber ASC
";

$stmt = $GLOBALS['con']->prepare($sql) or die(mysqli_error($GLOBALS['con']));
$bindTypes = 'i' . str_repeat('i', count($chainItems));
$bindValues = array_merge([$clientnumber], $chainItems);
$stmt->bind_param($bindTypes, ...$bindValues);
$stmt->execute();
$rs = $stmt->get_result();
$stmt->close();

$latestReports = [];
$latestNonPnaReports = [];
$reportSql = "
    SELECT itemnumber, repitem, repnumber, reptype, result, reportdata
    FROM reportitems
    WHERE clientnumber = ?
      AND itemnumber IN ($itemPlaceholders)
    ORDER BY itemnumber ASC, ABS(repitem) DESC
";
$reportStmt = $GLOBALS['con']->prepare($reportSql) or die(mysqli_error($GLOBALS['con']));
$reportStmt->bind_param($bindTypes, ...$bindValues);
$reportStmt->execute();
$reportRs = $reportStmt->get_result();
$reportStmt->close();

while ($reportRs && ($reportRow = $reportRs->fetch_assoc())) {
    $reportItem = (int)($reportRow['itemnumber'] ?? 0);
    if ($reportItem <= 0) {
        continue;
    }

    if (!isset($latestReports[$reportItem])) {
        $latestReports[$reportItem] = $reportRow;
    }

    $isPna = strtoupper(trim((string)($reportRow['result'] ?? ''))) === 'PNA';
    $isPnaType = trim((string)($reportRow['reptype'] ?? '')) === '503';
    if (!$isPna && !$isPnaType && !isset($latestNonPnaReports[$reportItem])) {
        $latestNonPnaReports[$reportItem] = $reportRow;
    }
}

$rows = [];
while ($rs && ($r = $rs->fetch_assoc())) {
    $itemnumber = (int)($r['itemnumber'] ?? 0);
    $lastReport = $latestReports[$itemnumber] ?? null;
    $lastNonPna = $latestNonPnaReports[$itemnumber] ?? null;

    $r['last_repnumber'] = $lastReport['repnumber'] ?? null;
    $r['last_examType'] = $lastReport['reptype'] ?? null;
    $r['last_result'] = $lastReport['result'] ?? null;
    $r['last_reportdata'] = $lastReport['reportdata'] ?? '';
    $r['last_reptype'] = $lastReport['reptype'] ?? '';
    $r['last_non_pna_repnumber'] = $lastNonPna['repnumber'] ?? null;
    $r['has_reports'] = $lastReport ? 1 : 0;

    $lastResult = strtoupper(trim((string)($r['last_result'] ?? ($r['lastReport'] ?? ''))));
    $lastExamType = trim((string)($r['last_examType'] ?? ''));
    $r['pna_initial'] = (($lastResult === 'PNA' || $lastExamType === '503') && empty($r['last_non_pna_repnumber'])) ? 1 : 0;

    $rd = enrepReportDataFromRow(['reportdata' => $r['last_reportdata'] ?? '']);
    $r['last_adefect'] = $rd['adefect'] ?? '';
    $r['last_bdefect'] = $rd['bdefect'] ?? '';
    $r['last_obs'] = $rd['obs'] ?? '';
    $rows[] = $r;
}

function rr_statusMeta($due): array
{
    $now = time();
    $due = is_numeric($due) ? intval($due) : 0;
    if ($due <= 0) return ['secondary-color', 'Unknown'];
    if ($due < $now) return ['danger-color-dark', 'Overdue'];
    if ($due < $now + 30 * 24 * 3600) return ['warning-color-dark', 'Pending'];
    return ['success-color-dark', 'Not Due'];
}

function rr_resultMeta($val): array
{
    $lr = strtoupper(trim((string)$val));
    return match ($lr) {
        'DEFECTS' => ['warning-color-dark', 'DEFECTS'],
        'URGENT'  => ['danger-color-dark', 'URGENT'],
        'PASS'    => ['success-color-dark', 'PASS'],
        'OBS'     => ['special-color', 'OBS'],
        'PNA'     => ['stylish-color-dark', 'PNA'],
        default   => ['secondary-color', ($lr !== '' ? $lr : '—')],
    };
}


$rrShow = [
    'description'  => (function_exists('asset_visible') ? asset_visible('description') : true),
    'plantnumber'  => (function_exists('asset_visible') ? asset_visible('plantnumber') : true),
    'serialnumber' => (function_exists('asset_visible') ? asset_visible('serialnumber') : true),
    'locname'      => (function_exists('asset_visible') ? asset_visible('locname') : true),
    'subloc'       => (function_exists('asset_visible') ? asset_visible('subloc') : true),
    'postcode'     => (function_exists('asset_visible') ? asset_visible('postcode') : true),
    'lastReport'   => (function_exists('asset_visible') ? asset_visible('lastReport') : true),
    'duedate'      => (function_exists('asset_visible') ? asset_visible('duedate') : true),
];

// Fixed columns: status + details + selector
$rrColspan = 3
    + ($rrShow['description'] ? 1 : 0)
    + ($rrShow['plantnumber'] ? 1 : 0)
    + ($rrShow['serialnumber'] ? 1 : 0)
    + ($rrShow['locname'] ? 1 : 0)
    + ($rrShow['subloc'] ? 1 : 0)
    + ($rrShow['postcode'] ? 1 : 0)
    + ($rrShow['lastReport'] ? 1 : 0)
    + ($rrShow['duedate'] ? 1 : 0)
    + 1; // actions

$table = '';
foreach ($rows as $r) {
    $itemnumber = intval($r['itemnumber']);
    $desc = htmlspecialchars((string)$r['desc']);
    $plant = htmlspecialchars((string)$r['plantnumber']);
    $serial = htmlspecialchars((string)$r['serialnumber']);
    $locname = htmlspecialchars((string)($r['locname'] ?? 'Unknown location'));
    $subloc = htmlspecialchars((string)($r['subloc'] ?? ''));
    $postcode = htmlspecialchars((string)($r['postcode'] ?? ''));
    $due = is_numeric($r['duedate']) ? date('d-m-Y', intval($r['duedate'])) : 'NDS';
    [$statusCol, $statusTitle] = rr_statusMeta($r['duedate']);

    $lrVal = $r['last_result'] ?? ($r['lastReport'] ?? '');
    [$resultCol, $resultText] = rr_resultMeta($lrVal);

    // ===== LOCK LOGIC (UPDATED): use LAST reportitems.reptype =====
    $hasReports = intval($r['has_reports'] ?? 0);

    $lastReptype = trim((string)($r['last_reptype'] ?? '')); // from reportitems
    $displayReptype = $lastReptype;

    // If there are no reports yet, do NOT lock based on reptype (unlocked by default)
    $lockedOut = false;
    $lockedReason = '';

    if ($hasReports === 1) {
        // Strict check; ensure DB stores these as exact strings like "500"
        $lockedOut = (!in_array($lastReptype, $rapidLockReptypes, true));
        $lockedReason = $lockedOut
            ? ('Locked: last report type ' . htmlspecialchars($lastReptype ?: 'unknown') . ' not permitted for RapidRep')
            : '';
    }
    // ================================================

    $lastExamType = is_numeric($r['last_examType']) ? intval($r['last_examType']) : 0;
    $lastRep = is_numeric($r['last_repnumber']) ? intval($r['last_repnumber']) : 0;
    $lastNonPna = is_numeric($r['last_non_pna_repnumber']) ? intval($r['last_non_pna_repnumber']) : 0;
    $pnaInitial = intval($r['pna_initial'] ?? 0);

    // keep statuslive gating
    $checkDisabled = ($lockedOut || intval($r['statuslive']) !== 1) ? 'disabled' : '';
    $rowMuted = ($checkDisabled !== '') ? 'opacity-50' : '';

    $lastA = trim((string)($r['last_adefect'] ?? ''));
    $lastB = trim((string)($r['last_bdefect'] ?? ''));
    $lastO = trim((string)($r['last_obs'] ?? ''));

    $fmt = function (string $v): string {
        $v = trim($v);
        if ($v === '' || strtolower($v) === 'none') return '<span class="text-muted">None</span>';
        return nl2br(htmlspecialchars($v));
    };

    $detailHtml = '
<div class="p-3">
  <div class="row g-3">
    <div class="col-12">

      <div class="fw-bold mb-1">'
        . htmlspecialchars($desc, ENT_QUOTES, "UTF-8") .
        ' <span class="text-muted">(#' . $itemnumber . ')</span>
      </div>';

    if (asset_visible('plantnumber') || asset_visible('serialnumber')) {
        $detailHtml .= '
      <div class="small text-muted mb-2">';
        if (asset_visible('plantnumber')) {
            $detailHtml .= '<b>' . htmlspecialchars(asset_label('plantnumber', 'Plant No.'), ENT_QUOTES, "UTF-8") . ':</b> ' . htmlspecialchars($plant) . ' ';
        }
        if (asset_visible('serialnumber')) {
            $detailHtml .= '&nbsp; <b>' . htmlspecialchars(asset_label('serialnumber', 'Serial'), ENT_QUOTES, "UTF-8") . ':</b> ' . htmlspecialchars($serial);
        }
        $detailHtml .= '
      </div>';
    }

    $detailHtml .= '
      <div class="d-lg-none small border-top pt-2 mt-2">';

    if (asset_visible('subloc')) {
        $detailHtml .= '
        <div class="mb-1">
          <b>' . htmlspecialchars(asset_label('subloc', 'Sub-location'), ENT_QUOTES, "UTF-8") . ':</b>
          ' . ($subloc !== '' ? htmlspecialchars($subloc) : '<span class="text-muted">—</span>') . '
        </div>';
    }

    if (asset_visible('postcode')) {
        $detailHtml .= '
        <div class="mb-1">
          <b>' . htmlspecialchars(asset_label('postcode', 'Post Code'), ENT_QUOTES, "UTF-8") . ':</b>
          ' . ($postcode !== '' ? htmlspecialchars($postcode) : '<span class="text-muted">—</span>') . '
        </div>';
    }

    if (asset_visible('duedate')) {
        $detailHtml .= '
        <div class="mb-2">
          <b>' . htmlspecialchars(asset_label('duedate', 'Due'), ENT_QUOTES, "UTF-8") . ':</b>
          ' . htmlspecialchars($due) . '
        </div>';
    }

    $detailHtml .= '
        <div class="d-flex gap-2 flex-wrap">
          <a href="javascript:void(0)" class="btn btn-info btn-sm formButton"
            data-values="' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '"
            data-href="' . ROOT_URL . '/includes/master/form.php"
            data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="New Report">
            <i class="fad fa-file-alt"></i>
          </a>

          <a href="index.php?t=includes/master&p=items.php&data=' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '&view=list"
            class="btn btn-secondary btn-sm"
            data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Completed Reports">
            <i class="fad fa-copy"></i>
          </a>

          <a href="index.php?t=includes/master&p=asset.php&view=edit_attached&data=' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '"
            class="btn btn-secondary btn-sm"
            data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Item Details">
            <i class="fad fa-info-circle"></i>
          </a>
        </div>
      </div>
    </div>

    <div class="row border-top">
      <div class="col-12 col-lg-4">
        <div class="small fw-bold mb-1 text-danger">A Defects</div>
        <div class="small rr-clamp">' . $fmt($lastA) . '</div>
      </div>

      <div class="col-12 col-lg-4">
        <div class="small fw-bold mb-1 text-warning">B Defects</div>
        <div class="small rr-clamp">' . $fmt($lastB) . '</div>
      </div>

      <div class="col-12 col-lg-4">
        <div class="small fw-bold mb-1 text-dark">Observations</div>
        <div class="small rr-clamp">' . $fmt($lastO) . '</div>
      </div>
    </div>

  </div>
</div>';

    $pnaStripStyle = '';

    if (strtoupper(trim((string)($r['lastReport'] ?? ''))) === 'PNA') {
        $diagColour = '#6c757d';

        if ($statusCol === 'danger-color-dark') {
            $diagColour = '#c00';
        } elseif ($statusCol === 'warning-color-dark') {
            $diagColour = '#f80';
        } elseif ($statusCol === 'success-color-dark') {
            $diagColour = '#007e33';
        }

        $pnaStripStyle = 'background:linear-gradient(to bottom right, ' . $diagColour . ' 0 50%, #000 50% 100%);';
    }
    $rowHtml = '
<tr class="rr-main-row ' . $rowMuted . '" id="rr_' . $itemnumber . '"
    data-itemnumber="' . $itemnumber . '"
    data-reptype="' . htmlspecialchars($displayReptype) . '"
    data-locked="' . ($lockedOut ? '1' : '0') . '"
    data-locked-reason="' . $lockedReason . '"
    data-has-reports="' . $hasReports . '"
    data-last-examtype="' . $lastExamType . '"
    data-last-rep="' . $lastRep . '"
    data-last-nonpna-rep="' . $lastNonPna . '"
    data-last-result="' . htmlspecialchars(strtoupper((string)$lrVal)) . '"
    data-pna-initial="' . $pnaInitial . '"
    data-desc="' . htmlspecialchars((string)$r['desc'], ENT_QUOTES, 'UTF-8') . '"
    data-plant="' . htmlspecialchars((string)$r['plantnumber'], ENT_QUOTES, 'UTF-8') . '"
    data-serial="' . htmlspecialchars((string)$r['serialnumber'], ENT_QUOTES, 'UTF-8') . '"
>
 <td class="p-0 status-col col-status status_colour ' . ($pnaStripStyle === '' ? $statusCol : '') . '"
    style="width:20px;' . $pnaStripStyle . '"
    data-mdb-tooltip-init
    data-mdb-placement="top"
    data-mdb-trigger="hover"
    title="' . htmlspecialchars($statusTitle) . '">
    ' . ($lockedOut ? '<button type="button" class="rr-lock-info" onclick="rrLockedInfoModal(' . $itemnumber . ')" aria-label="RapidRep locked"><i class="fad fa-lock-alt"></i></button>' : '') . '
</td>

  <td class="text-center col-toggle" style="width:34px">
    <button type="button" class="btn btn-secondary btn-sm rr-detail-toggle"
      data-item="' . $itemnumber . '"
      data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="View details">
      <i class="fad fa-circle-info"></i>
    </button>
  </td>

  <td class="text-center col-select" style="width:44px">
    <div class="form-check m-0 d-flex justify-content-center">
      <input class="form-check-input rr-check ms-n4 " type="checkbox"  value="' . $itemnumber . '" id="rr_cb_' . $itemnumber . '" ' . $checkDisabled . '>
    </div>
  </td>
';

    if ($rrShow['description']) {
        $rowHtml .= '
  <td class="col-desc">
    <div class="d-flex align-items-center gap-2">
      <label class="m-0 rr-row-label" for="rr_cb_' . $itemnumber . '">
        ' . $desc . '
        <div class="small text-muted">#' . $itemnumber . '</div>
      </label>
    </div>
  </td>
';
    }

    if ($rrShow['plantnumber'])  $rowHtml .= '  <td class="col-plant">' . $plant . '</td>' . "
";
    if ($rrShow['serialnumber']) $rowHtml .= '  <td class="col-serial">' . $serial . '</td>' . "
";
    if ($rrShow['locname'])      $rowHtml .= '  <td class="col-location">' . $locname . '</td>' . "
";
    if ($rrShow['subloc'])       $rowHtml .= '  <td class="col-subloc">' . $subloc . '</td>' . "
";
    if ($rrShow['postcode'])     $rowHtml .= '  <td class="col-postcode">' . $postcode . '</td>' . "
";

    if ($rrShow['lastReport']) {
        $rowHtml .= '
  <td class="text-center col-result">
    <span class="badge ' . $resultCol . ' text-light">' . htmlspecialchars($resultText) . '</span>
  </td>
';
    }

    if ($rrShow['duedate']) $rowHtml .= '  <td class="col-due">' . htmlspecialchars($due) . '</td>' . "
";

    $rowHtml .= '
  <td class="text-center col-actions">
    <div class="d-flex justify-content-center gap-2 flex-wrap">
      <a href="javascript:void(0)" class="btn btn-info btn-sm formButton"
        data-values="' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '"
        data-href="' . ROOT_URL . '/includes/master/form.php"
        data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="New Report">
        <i class="fad fa-file-alt"></i>
      </a>

      <a href="index.php?t=includes/master&p=items.php&data=' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '&view=list"
        class="btn btn-secondary btn-sm"
        data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Completed Reports">
        <i class="fad fa-copy"></i>
      </a>

      <a href="index.php?t=includes/master&p=asset.php&view=edit_attached&data=' . $clientnumber . '|' . intval($r['locnumber']) . '|' . $itemnumber . '"
        class="btn btn-secondary btn-sm"
        data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover" title="Item Details">
        <i class="fad fa-info-circle"></i>
      </a>
    </div>
  </td>
</tr>

<tr id="rr_detail_' . $itemnumber . '" class="rr-detail-row" style="display:none">
  <td colspan="' . (int)$rrColspan . '">' . $detailHtml . '</td>
</tr>';

    $table .= $rowHtml;
}
?>

<style>
#rrTable>tbody>tr>td {
    vertical-align: middle
}

#rrTable th.col-status,
#rrTable td.col-status {
    width: 20px;
    min-width: 20px;
    max-width: 20px;
    padding: 0 !important;
    position: relative;
}

.rr-lock-info {
    width: 20px;
    height: 100%;
    min-height: 32px;
    border: 0;
    padding: 0;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, .35);
    color: #fff;
    cursor: pointer;
}

.rr-lock-info:hover,
.rr-lock-info:focus {
    background: rgba(0, 0, 0, .55);
    color: #fff;
    outline: none;
}

#rrTable th.col-toggle,
#rrTable td.col-toggle {
    width: 34px;
    min-width: 34px;
    max-width: 34px;
}


#rrTable th.col-select,
#rrTable td.col-select {
    width: 44px;
    min-width: 44px;
    max-width: 44px;
    text-align: center;
    vertical-align: middle;
}

#rrTable td.col-select {
    padding: 0 !important;
}

#rrTable td.col-select .form-check-input {
    margin: 0;
}


/* Keep the details (info) button contained and centred in its cell */
#rrTable td.col-toggle {
    padding: 0 !important;
    text-align: center;
    vertical-align: middle;
}

#rrTable td.col-toggle .rr-detail-toggle {
    width: 28px;
    height: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

#rrTable td.col-toggle .rr-detail-toggle i {
    line-height: 1;
}

.rr-clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
    word-break: break-word
}

#rrTable tbody tr.rr-detail-row td.bg-white {
    background-color: inherit !important
}

#rrTable tbody tr.rr-main-row:nth-child(4n+1)>td:not(.col-status) {
    background-color: rgba(0, 0, 0, .06) !important
}

#rrTable tbody tr.rr-main-row:nth-child(4n+3)>td:not(.col-status) {
    background-color: rgba(0, 0, 0, .015) !important
}

#rrTable tbody tr.rr-main-row.rr-selected:nth-child(4n+1)>td:not(.col-status) {
    background-color: rgba(13, 110, 253, .95) !important;
    color: #fff !important
}

#rrTable tbody tr.rr-main-row.rr-selected:nth-child(4n+3)>td:not(.col-status) {
    background-color: rgb(13, 110, 253) !important;
    color: #fff !important
}

#rrTable tbody tr.rr-main-row.rr-selected .text-muted,
#rrTable tbody tr.rr-main-row.rr-selected .small,
#rrTable tbody tr.rr-main-row.rr-selected .rr-row-label {
    color: rgba(255, 255, 255, .92) !important
}

#rrTable tbody tr.rr-main-row.rr-selected>td * {
    background-color: transparent !important;
    color: inherit !important
}

#rrTable tbody tr.rr-main-row.rr-selected .bg-white {
    background-color: transparent !important
}

#rrTable tbody tr.rr-main-row.rr-selected:nth-child(4n+1)+tr.rr-detail-row>td {
    background-color: rgba(13, 110, 253, .95) !important;
    color: #fff !important
}

#rrTable tbody tr.rr-main-row.rr-selected:nth-child(4n+3)+tr.rr-detail-row>td {
    background-color: rgb(13, 110, 253) !important;
    color: #fff !important
}

#rrTable tbody tr.rr-main-row.rr-selected+tr.rr-detail-row .text-muted,
#rrTable tbody tr.rr-main-row.rr-selected+tr.rr-detail-row .small {
    color: rgba(255, 255, 255, .92) !important
}


@media (max-width: 991.98px) {

    /* Keep table layout on mobile (no card mode). Hide low-priority columns and show them in the details row. */
    #rrTable thead th.col-subloc,
    #rrTable thead th.col-postcode,
    #rrTable thead th.col-due,
    #rrTable thead th.col-actions,
    #rrTable tbody td.col-subloc,
    #rrTable tbody td.col-postcode,
    #rrTable tbody td.col-due,
    #rrTable tbody td.col-actions {
        display: none;
    }

    /* Preserve fixed widths for colour + details button columns */
    #rrTable th.col-status,
    #rrTable td.col-status {
        width: 20px !important;
        min-width: 20px !important;
        max-width: 20px !important;
        padding: 0 !important;
    }

    #rrTable th.col-toggle,
    #rrTable td.col-toggle {
        width: 34px !important;
        min-width: 34px !important;
        max-width: 34px !important;
        padding: 0 !important;

        #rrTable th.col-select,
        #rrTable td.col-select {
            width: 44px !important;
            min-width: 44px !important;
            max-width: 44px !important;
            padding: 0 !important;
            text-align: center;
            vertical-align: middle;
        }

    }

    /* Mobile must NOT force horizontal scroll; clamp table to viewport and allow wrapping */
    .rr-table-wrap {
        overflow-x: hidden !important;
    }

    #rrTable {
        width: 100% !important;
        min-width: 0 !important;
        table-layout: fixed !important;
    }

    #rrTable th,
    #rrTable td {
        white-space: normal !important;
        overflow-wrap: anywhere !important;
        word-break: break-word !important;
    }

    #rrTable td.col-desc,
    #rrTable td.col-desc .rr-row-label {
        overflow-wrap: normal !important;
        word-break: normal !important;
    }

    #rrTable th.rr-sortable {
        white-space: normal !important;
    }

    /* Keep details button centred in its cell and away from the checkbox */
    #rrTable td.col-toggle {
        text-align: center;
    }

    #rrTable td.col-toggle .btn,
    #rrTable td.col-toggle button {
        margin: 4px auto !important;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

.rr-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.rr-sort-ind {
    display: inline-block;
    margin-left: 6px;
    font-size: 0.85em;
    opacity: 0.9;
}

th.rr-sortable.rr-sorted-asc .rr-sort-ind::after {
    content: "▲";
}

th.rr-sortable.rr-sorted-desc .rr-sort-ind::after {
    content: "▼";
}

.rr-linked-help-titlebar {
    align-items: center;
    display: flex;
    gap: 10px;
}

.rr-linked-help-titlebar strong {
    min-width: 0;
}

.rr-linked-help-titlebar>.help-icon {
    align-items: center !important;
    background: #ffffff !important;
    border: 2px solid #1f2d3d !important;
    border-radius: 50% !important;
    color: #1f2d3d !important;
    display: inline-flex !important;
    flex: 0 0 28px !important;
    font-weight: 700 !important;
    height: 28px !important;
    justify-content: center !important;
    margin-left: auto !important;
    min-width: 28px !important;
    padding: 0 !important;
}

.rr-linked-help-titlebar>.help-icon:hover,
.rr-linked-help-titlebar>.help-icon:focus {
    background: #1f2d3d !important;
    color: #ffffff !important;
}
</style>

<div id="loadingObject" style="position: fixed; top:50%; width:100%">
    <h1 class="text-center">
        <i class="fad fa-flux-capacitor fa-spin fa-3x fa-fw"
            style="--fa-primary-color:#0055A6;--fa-secondary-color:gray;"></i><br>
        Loading Data<br><small>Please wait</small>
    </h1>
</div>

<div id="data" style="display:none">
    <div class="row align-items-end g-2 mb-3">
        <div class="col-12 col-lg-7 note note-light rr-linked-help-titlebar"
            data-help-topic="rapid_report_system">
            <strong>
                <i class="fad fa-link"></i> <span id="rrChainTitle"><?= $chainTitle ?></span> &mdash;
                <span class="text-muted">Viewing <?= htmlspecialchars($seedRow['desc'] ?? '') ?> and its linkages</span>
            </strong>
            <?php if ((int)$chainId > 0) { ?>
            <a href="javascript:void(0)" class="btn btn-light btn-sm px-2 py-0 ms-2 align-middle"
                onclick="rrOpenRenameChain()" data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                title="Rename chain">
                <i class="fad fa-pencil"></i>
            </a>
            <?php } ?>
            <span class="small text-muted ms-2">RapidRep is optimised for large selections (up to ~500 items).</span>
        </div>
    </div>

    <div class="d-flex align-items-center justify-content-between flex-wrap gap-2 mb-2">
        <div class="d-flex gap-2">
            <button type="button" id="rrSelectAllBtn" class="btn btn-secondary btn-sm" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Select all available items">
                <i class="fad fa-check-double"></i> Select All
            </button>

            <button type="button" id="rrDeselectAllBtn" class="btn btn-light btn-sm" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Deselect all items">
                <i class="fad fa-square-minus"></i> Deselect All
            </button>

            <button type="button" id="rrToggleAllDetails" class="btn btn-secondary btn-sm ms-4" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Show / hide all details">
                <i id="rrDetailIcon" class="fad fa-bars me-2"></i> View Details
            </button>
        </div>
        <div class="d-flex gap-2">
            <button type="button" id="rrRapidBtn" class="btn btn-secondary btn-sm" style="display:none"
                data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                title="Rapid report selected items">
                <i class="fad fa-copy"></i> Rapid Report
            </button>
            <button type="button" id="rrPnaBtn" class="btn btn-dark btn-sm" style="display:none" data-mdb-tooltip-init
                data-mdb-placement="top" data-mdb-trigger="hover" title="Register selected items as PNA">
                <i class="fad fa-subtitles-slash"></i> PNA Items
            </button>
            <?= $repRewind ?>
        </div>
    </div>
    <div class="row g-2 align-items-center mt-2">
        <div class="col-12 col-md-8 col-lg-6">
            <div class="input-group">
                <span class="input-group-text bg-secondary text-light" data-mdb-tooltip-init data-mdb-placement="top"
                    data-mdb-trigger="hover" title="Search description, plant number, or serial">
                    <i class="fad fa-magnifying-glass"></i>
                </span>

                <input type="text" id="rrSearch" class="form-control" placeholder="Search description / plant / serial"
                    autocomplete="off">

                <button type="button" id="rrSearchBtn" class="btn btn-secondary" data-mdb-tooltip-init
                    data-mdb-placement="top" data-mdb-trigger="hover" title="Search">
                    Search
                </button>

                <button type="button" id="rrSearchClear" class="btn btn-light" data-mdb-tooltip-init
                    data-mdb-placement="top" data-mdb-trigger="hover" title="Clear search">
                    <i class="fad fa-xmark"></i>
                </button>
            </div>

            <div class="small text-muted mt-1">
                Type at least 2 characters to filter.
                <span id="rrSearchCount"></span>
            </div>
        </div>
    </div>

    <div class="rr-table-wrap">


        <table id="rrTable" class="table table-bordered table-hover table-sm mt-4" style="width:100%">

            <thead class="table-dark">
                <tr>
                    <th class="col-status"></th>
                    <th class="col-toggle"></th>

                    <th class="col-select text-center" style="width:44px;"></th>

                    <?php if (function_exists('asset_visible') && asset_visible('description')): ?>
                    <th class="col-desc rr-sortable" data-sort-col="desc" role="button">
                        <?= htmlspecialchars(asset_label('description', 'Description'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('plantnumber')): ?>
                    <th class="col-plant rr-sortable" data-sort-col="plant" role="button">
                        <?= htmlspecialchars(asset_label('plantnumber', 'Plant No.'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('serialnumber')): ?>
                    <th class="col-serial rr-sortable" data-sort-col="serial" role="button">
                        <?= htmlspecialchars(asset_label('serialnumber', 'Serial'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('locname')): ?>
                    <th class="col-location rr-sortable" data-sort-col="location" role="button">
                        <?= htmlspecialchars(asset_label('locname', 'Location'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('subloc')): ?>
                    <th class="col-subloc rr-sortable" data-sort-col="subloc" role="button">
                        <?= htmlspecialchars(asset_label('subloc', 'Sub-location'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('postcode')): ?>
                    <th class="col-postcode rr-sortable" data-sort-col="postcode" role="button">
                        <?= htmlspecialchars(asset_label('postcode', 'Post Code'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('lastReport')): ?>
                    <th class="col-result text-center rr-sortable" data-sort-col="result" role="button">
                        <?= htmlspecialchars(asset_label('lastReport', 'Result'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <?php if (function_exists('asset_visible') && asset_visible('duedate')): ?>
                    <th class="col-due rr-sortable" data-sort-col="due" role="button">
                        <?= htmlspecialchars(asset_label('duedate', 'Due'), ENT_QUOTES, 'UTF-8'); ?> <span
                            class="rr-sort-ind"></span>
                    </th>
                    <?php endif; ?>

                    <th class="col-actions text-center">Actions</th>
                </tr>
            </thead>


            <tbody><?= $table ?></tbody>
        </table>
    </div>

    <div class="rr-sticky-actions p-2 mt-3">
        <div class="d-flex flex-wrap align-items-center justify-content-between gap-2">
            <div class="small">
                Selected: <b id="rrSelectedCount">0</b>
                <span class="text-muted ms-2">Locked rows cannot be selected.</span>
            </div>
            <div class="d-flex gap-2">
                <button type="button" id="rrClearBtn" class="btn btn-light" data-mdb-tooltip-init
                    data-mdb-placement="top" data-mdb-trigger="hover" title="Clear selection">
                    <i class="fad fa-xmark"></i> Clear
                </button>

                <button type="button" id="rrRapidBtn2" class="btn btn-secondary" style="display:none"
                    data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                    title="Rapid report selected items">
                    <i class="fad fa-copy"></i> Rapid Report
                </button>
                <button type="button" id="rrPnaBtn2" class="btn btn-dark" style="display:none" data-mdb-tooltip-init
                    data-mdb-placement="top" data-mdb-trigger="hover" title="Register selected items as PNA">
                    <i class="fad fa-subtitles-slash"></i> PNA Items
                </button>
            </div>
        </div>
    </div>
</div>

<script>
if (document.getElementById('navBox')) {
    document.getElementById('navBox').innerHTML =
        '<li class="breadcrumb-item"><a href="index.php?t=includes/master&p=client.php&view=list">Client List</a><i class="fad fa-angle-double-right mx-2 mt-1" aria-hidden="true"></i></li>' +
        '<li class="breadcrumb-item"><?= addslashes(getClientName($clientnumber)) ?><i class="fad fa-angle-double-right mx-2 mt-1" aria-hidden="true"></i></li>' +
        '<li class="breadcrumb-item"><a href="index.php?t=includes/master&p=client.php&clientnumber=<?= $clientnumber ?>&view=asset">Schedule</a><i class="fad fa-angle-double-right mx-2 mt-1" aria-hidden="true"></i></li>' +
        '<li class="breadcrumb-item active">Linked Items</li>';
}

// ---------- SEARCH (desc/plant/serial) ----------
const rrSearchInput = document.getElementById('rrSearch');
const rrSearchBtn = document.getElementById('rrSearchBtn');
const rrSearchClear = document.getElementById('rrSearchClear');
const rrSearchCount = document.getElementById('rrSearchCount');

function rrRowSearchText(mainRow) {
    const d = mainRow.querySelector('td.col-desc')?.textContent || '';
    const p = mainRow.querySelector('td.col-plant')?.textContent || '';
    const s = mainRow.querySelector('td.col-serial')?.textContent || '';
    return (d + ' ' + p + ' ' + s).toLowerCase();
}

function rrApplySearch(termRaw) {
    if (!rrTable) return;
    const term = String(termRaw || '').trim().toLowerCase();

    const tbody = rrTable.querySelector('tbody');
    if (!tbody) return;

    let shown = 0;
    let total = 0;

    const mains = tbody.querySelectorAll('tr.rr-main-row');
    mains.forEach(mainRow => {
        total++;

        const item = mainRow.getAttribute('data-itemnumber');
        const detailRow = item ? document.getElementById('rr_detail_' + item) : null;

        const passes =
            (term.length < 2) ? true : rrRowSearchText(mainRow).includes(term);

        mainRow.style.display = passes ? '' : 'none';
        if (detailRow) {
            // hide detail rows when parent is hidden; preserve state when shown
            if (!passes) detailRow.style.display = 'none';
        }

        if (passes) shown++;
    });

    if (rrSearchCount) {
        rrSearchCount.textContent = `(${shown}/${total})`;
    }
}

let rrSearchTimer = null;

function rrSearchAsYouType() {
    if (!rrSearchInput) return;
    clearTimeout(rrSearchTimer);
    rrSearchTimer = setTimeout(() => {
        rrApplySearch(rrSearchInput.value);
    }, 150);
}

if (rrSearchInput) {
    rrSearchInput.addEventListener('input', rrSearchAsYouType);
    rrSearchInput.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            rrApplySearch(rrSearchInput.value);
        }
        if (e.key === 'Escape') {
            rrSearchInput.value = '';
            rrApplySearch('');
        }
    });
}

if (rrSearchBtn) rrSearchBtn.addEventListener('click', () => rrApplySearch(rrSearchInput ? rrSearchInput.value : ''));
if (rrSearchClear) rrSearchClear.addEventListener('click', () => {
    if (rrSearchInput) rrSearchInput.value = '';
    rrApplySearch('');
});
// initialise count
rrApplySearch('');
// ---------- /SEARCH ----------


const RR = {
    clientnumber: <?= (int)$clientnumber ?>,
    seedItem: <?= (int)$seedItem ?>,
    chainId: <?= json_encode((string)$chainId) ?>,
    chainName: <?= json_encode((string)$chainDesc, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
    renameEndpoint: <?= json_encode(ROOT_URL . '/includes/master/linked_name.php') ?>,
    allowedReptypes: <?= json_encode($allowedReptypesMeta) ?>,
};

function rrEscapeHtml(value) {
    return String(value ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

function rrLockedInfoModal(itemnumber) {
    const row = document.getElementById('rr_' + itemnumber);
    if (!row) return;

    const reason = row.dataset.lockedReason || 'This item is locked for RapidRep.';
    const desc = row.dataset.desc || '';
    const plant = row.dataset.plant || '';
    const serial = row.dataset.serial || '';
    const lastType = row.dataset.reptype || 'unknown';

    const html = `
      <div class="mb-3">
        <div class="fw-bold mb-1">${rrEscapeHtml(desc || 'Item #' + itemnumber)}</div>
        <div class="small text-muted">
          Item #${rrEscapeHtml(itemnumber)}
          ${plant ? ' | Plant: ' + rrEscapeHtml(plant) : ''}
          ${serial ? ' | Serial: ' + rrEscapeHtml(serial) : ''}
        </div>
      </div>

      <div class="alert alert-warning mb-3">
        <div class="fw-bold mb-1">RapidRep locked</div>
        <div>${rrEscapeHtml(reason)}</div>
      </div>

      <div class="small text-muted">
        RapidRep can only process items whose last report type is in the permitted RapidRep list.
        This item's last report type is <b>${rrEscapeHtml(lastType)}</b>, so it must be handled through the normal report route.
      </div>
    `;

    loadModalContent(html, 'rapidLockBox', 'modal-md', 1070, 'true', 'RapidRep Lock Information', 'close');
}

function rrOpenRenameChain() {
    const html = `
            <div class="mb-3">
                <label for="rrChainName" class="form-label">Chain name</label>
                <input type="text" id="rrChainName" class="form-control" value="${rrEscapeHtml(RR.chainName)}" maxlength="120">
            </div>
        `;

    loadModalContent(html, 'popupBox', 'modal-sm', 1060, 'true', 'Rename Chain', 'cancelConfirm',
        () => rrRenameChain());

    setTimeout(() => {
        const input = document.getElementById('rrChainName');
        if (input) {
            input.focus();
            input.select();
        }
    }, 250);
}

async function rrRenameChain() {
    const input = document.getElementById('rrChainName');
    const newName = input ? input.value.trim() : '';

    if (!newName) {
        if (typeof showResponse === 'function') showResponse('warning', 'Please enter a chain name.');
        return;
    }

    if (typeof killModal === 'function') {
        killModal('popupBox');
    } else if (window.$) {
        $('#popupBox').modal('hide');
    }

    const body = new URLSearchParams();
    body.set('FUNCTION', 'rename');
    body.set('clientnumber', String(RR.clientnumber));
    body.set('chain', String(RR.chainId || ''));
    body.set('name', newName);
    body.set('tenant', typeof TENANT_URL !== 'undefined' ? TENANT_URL : '');

    try {
        const response = await fetch(RR.renameEndpoint, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            },
            body
        });
        const payloadText = await response.text();
        let payload = null;
        try {
            payload = JSON.parse(payloadText);
        } catch (e) {
            payload = null;
        }

        if (!response.ok || !payload || !payload.ok) {
            const message = payload && payload.message ? payload.message : 'Unable to rename chain.';
            if (typeof showResponse === 'function') showResponse('danger', message);
            return;
        }

        RR.chainName = payload.name;
        const title = document.getElementById('rrChainTitle');
        if (title) title.textContent = payload.title;
        if (typeof showResponse === 'function') showResponse('success', 'Chain renamed.');
    } catch (e) {
        if (typeof showResponse === 'function') showResponse('danger', 'Network error while renaming chain.');
    }
}

function rrApplyRowSelectedState(tr, checked) {
    if (!tr) return;
    const item = tr.dataset.itemnumber;
    if (!item) return;
    const detail = document.getElementById('rr_detail_' + item);
    if (checked) {
        tr.classList.add('rr-selected');
        if (detail) detail.classList.add('rr-selected-detail');
    } else {
        tr.classList.remove('rr-selected');
        if (detail) detail.classList.remove('rr-selected-detail');
    }
}

function rrSyncAllSelectedClasses() {
    document.querySelectorAll('#rrTable tbody tr.rr-main-row').forEach(tr => {
        const item = tr.dataset.itemnumber;
        const cb = item ? document.getElementById('rr_cb_' + item) : null;
        rrApplyRowSelectedState(tr, !!(cb && cb.checked));
    });
}

function rrUpdateSelectedCount() {
    const c = document.querySelectorAll('.rr-check:checked').length;
    const el = document.getElementById('rrSelectedCount');
    if (el) el.textContent = String(c);

    const show = (c >= 2);

    const r1 = document.getElementById('rrRapidBtn');
    if (r1) r1.style.display = show ? 'inline-flex' : 'none';

    const r2 = document.getElementById('rrRapidBtn2');
    if (r2) r2.style.display = show ? 'inline-flex' : 'none';

    const p1 = document.getElementById('rrPnaBtn');
    if (p1) p1.style.display = show ? 'inline-flex' : 'none';

    const p2 = document.getElementById('rrPnaBtn2');
    if (p2) p2.style.display = show ? 'inline-flex' : 'none';

    rrSyncAllSelectedClasses();
}

function rrSelectAll() {
    // Select only visible rows (post-search filter)
    document.querySelectorAll('#rrTable tbody tr.rr-main-row').forEach(tr => {
        if (tr.style.display === 'none') return;
        const item = tr.dataset.itemnumber;
        const cb = item ? document.getElementById('rr_cb_' + item) : null;
        if (cb && !cb.disabled) cb.checked = true;
    });
    rrUpdateSelectedCount();
}

function rrDeselectAll() {
    // Deselect only visible rows (post-search filter)
    document.querySelectorAll('#rrTable tbody tr.rr-main-row').forEach(tr => {
        if (tr.style.display === 'none') return;
        const item = tr.dataset.itemnumber;
        const cb = item ? document.getElementById('rr_cb_' + item) : null;
        if (cb) cb.checked = false;
    });
    rrUpdateSelectedCount();
}

function rrClearAll() {
    document.querySelectorAll('.rr-check').forEach(cb => cb.checked = false);
    rrUpdateSelectedCount();
}

function rrGetSelectedRows() {
    const trs = [];
    document.querySelectorAll('.rr-check:checked').forEach(cb => {
        const tr = cb.closest('tr');
        if (tr && tr.classList.contains('rr-main-row')) trs.push(tr);
    });
    return trs;
}

function rrBuildRapidPayload() {
    const selectedRows = rrGetSelectedRows();
    if (selectedRows.length === 0) return null;

    const groups = {
        initialItems: [],
        standardCloneItems: [],
        pnaWithPriorCloneItems: [],
        pnaInitialItems: [],
        lockedOutItems: [],
    };

    selectedRows.forEach(tr => {
        const item = Number(tr.dataset.itemnumber || 0);
        const lastRep = Number(tr.dataset.lastRep || 0);
        const hasReports = Number(tr.dataset.hasReports || 0) || lastRep > 0;
        const lastExam = Number(tr.dataset.lastExamtype || 0);
        const lastNonPna = Number(tr.dataset.lastNonpnaRep || 0);
        const pnaInitial = Number(tr.dataset.pnaInitial || 0);
        const lastResult = String(tr.dataset.lastResult || '').toUpperCase();

        if (!item) return;

        if (!hasReports) {
            groups.initialItems.push(item);
            return;
        }

        const isPna = (lastExam === 503) || (lastResult === 'PNA');
        if (isPna) {
            if (lastNonPna > 0) groups.pnaWithPriorCloneItems.push(item);
            else groups.pnaInitialItems.push(item);
            return;
        }

        groups.standardCloneItems.push(item);
    });

    return groups;
}

function rrRapidClassificationLabel(tr) {
    const lastRep = Number(tr.dataset.lastRep || 0);
    const hasReports = Number(tr.dataset.hasReports || 0) || lastRep > 0;
    const lastExam = Number(tr.dataset.lastExamtype || 0);
    const lastNonPna = Number(tr.dataset.lastNonpnaRep || 0);
    const lastResult = String(tr.dataset.lastResult || '').toUpperCase();

    if (!hasReports) return 'initial';

    const isPna = (lastExam === 503) || (lastResult === 'PNA');
    if (isPna) {
        return lastNonPna > 0 ? 'pnaPrior' : 'pnaOnly';
    }

    return 'standard';
}

function rrEscapeHtml(value) {
    return String(value ?? '').replace(/[&<>"']/g, ch => ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    } [ch]));
}

function rrRapidClassificationModal() {
    const groups = {
        initial: [],
        pnaPrior: [],
        pnaOnly: [],
        standard: [],
    };

    rrGetSelectedRows().forEach(tr => {
        const key = rrRapidClassificationLabel(tr);
        groups[key].push({
            item: tr.dataset.itemnumber || '',
            desc: tr.dataset.desc || '',
            plant: tr.dataset.plant || '',
            serial: tr.dataset.serial || '',
        });
    });

    const renderGroup = (title, help, rows) => `
      <div class="mb-3">
        <div class="d-flex justify-content-between align-items-center mb-1">
          <div class="fw-bold text-dark">${title}</div>
          <span class="badge bg-secondary">${rows.length}</span>
        </div>
        <div class="small text-muted mb-2">${help}</div>
        ${rows.length ? `
          <div class="table-responsive">
            <table class="table table-sm table-striped mb-0">
              <thead>
                <tr>
                  <th style="width:90px">Item</th>
                  <th>Description</th>
                  <th style="width:150px">Plant</th>
                  <th style="width:150px">Serial</th>
                </tr>
              </thead>
              <tbody>
                ${rows.map(row => `
                  <tr>
                    <td>#${rrEscapeHtml(row.item)}</td>
                    <td>${rrEscapeHtml(row.desc || '-')}</td>
                    <td>${rrEscapeHtml(row.plant || '-')}</td>
                    <td>${rrEscapeHtml(row.serial || '-')}</td>
                  </tr>
                `).join('')}
              </tbody>
            </table>
          </div>
        ` : '<div class="text-muted small border p-2">No selected items in this category.</div>'}
      </div>
    `;

    const html = [
        groups.initial.length ? renderGroup('Initial',
            'Items with no previous report. These use the selected initial report type.', groups.initial) : '',
        groups.pnaPrior.length ? renderGroup('PNA with prior non-PNA',
            'Items whose last report is PNA and have an older non-PNA report available.', groups.pnaPrior) : '',
        groups.pnaOnly.length ? renderGroup('Only previous report is PNA',
            'Items whose only previous report is PNA.', groups.pnaOnly) : '',
        groups.standard.length ? renderGroup('Normal clone',
            'Items cloned from their latest non-PNA/non-initial report path.', groups.standard) : '',
    ].join('');

    loadModalContent(html, 'rapidClassBox', 'modal-xl', 1070, 'true', 'Rapid Report Item Breakdown', 'close');
}

function rrInitDatepickers(modalEl) {
    if (!modalEl || typeof mdb === 'undefined' || !mdb.Datepicker) return;
    const datepickerElements = modalEl.querySelectorAll(".date-picker");
    datepickerElements.forEach((datepickerEl) => {
        try {
            new mdb.Datepicker(datepickerEl, {
                confirmDateOnSelect: true,
                format: "dd-mm-yyyy"
            });
        } catch (e) {}
    });
}

function rrInitSurveyorSelect(modalEl) {
    if (!modalEl || typeof mdb === 'undefined' || !mdb.Select) return;
    const sel = modalEl.querySelector('#rr_surveyor');
    if (!sel) return;
    try {
        new mdb.Select(sel, {
            filter: true,
            container: "#rapidBox"
        });
    } catch (e) {}
}

function rrRapidModal() {
    const selectedRows = rrGetSelectedRows();
    if (selectedRows.length < 2) {
        showResponse('warning', 'Select at least 2 items for Rapid Report');
        return;
    }

    const groups = rrBuildRapidPayload();
    if (!groups) {
        showResponse('warning', 'No items selected');
        return;
    }

    const counts = {
        initial: groups.initialItems.length,
        standard: groups.standardCloneItems.length,
        pnaPrior: groups.pnaWithPriorCloneItems.length,
        pnaInitial: groups.pnaInitialItems.length,
        total: groups.initialItems.length + groups.standardCloneItems.length + groups.pnaWithPriorCloneItems
            .length + groups.pnaInitialItems.length
    };

    const needInitialType = (counts.initial > 0 || counts.pnaInitial > 0);
    const pnaPriorPanel = counts.pnaPrior > 0 ? `
      <div class="rr-pna-panel">
        <div class="rr-pna-panel-title">Last report is PNA</div>
        <div class="rr-inline-options">
          <div class="form-check">
            <input class="form-check-input" type="radio" name="rr_pna_mode" id="rr_pna_mode_pna" value="pna" checked>
            <label class="form-check-label" for="rr_pna_mode_pna">Create another PNA (503)</label>
          </div>
          <div class="form-check">
            <input class="form-check-input" type="radio" name="rr_pna_mode" id="rr_pna_mode_clone" value="clone_non_pna">
            <label class="form-check-label" for="rr_pna_mode_clone">Clone last non-PNA report</label>
          </div>
        </div>
        <div class="rr-compact-help mt-2">Affects <b>${counts.pnaPrior}</b> item(s) with a prior non-PNA report.</div>
      </div>
    ` : '';
    const pnaInitialPanel = counts.pnaInitial > 0 ? `
      <div class="rr-pna-panel">
        <div class="rr-pna-panel-title">Only previous report is PNA</div>
        <div class="rr-inline-options">
          <div class="form-check">
            <input class="form-check-input" type="radio" name="rr_pna_initial_mode" id="rr_pna_initial_mode_pna" value="pna" checked>
            <label class="form-check-label" for="rr_pna_initial_mode_pna">Create another PNA (503)</label>
          </div>
          <div class="form-check">
            <input class="form-check-input" type="radio" name="rr_pna_initial_mode" id="rr_pna_initial_mode_initial" value="initial">
            <label class="form-check-label" for="rr_pna_initial_mode_initial">Use initial report type</label>
          </div>
        </div>
        <div class="rr-compact-help mt-1">Affects <b>${counts.pnaInitial}</b> item(s) only.</div>
      </div>
    ` : '';

    const html = `
  <div id="rrRapidStart">
    <style>
      .rr-modal-summary {
        display: grid;
        grid-template-columns: repeat(5, minmax(0, 1fr));
        gap: 8px;
        margin-bottom: 12px;
      }
      .rr-summary-tile {
        border: 1px solid #d7dee7;
        border-left: 4px solid #29435d;
        padding: 7px 10px;
        min-height: 52px;
        background: #fff;
      }
      .rr-summary-tile strong {
        display: block;
        font-size: 18px;
        line-height: 20px;
      }
      .rr-summary-tile span {
        display: block;
        font-size: 12px;
        color: #607080;
        line-height: 16px;
      }
      .rr-rapid-section {
        border: 1px solid #dde3ea;
        background: #fff;
        padding: 10px 12px;
        margin-bottom: 10px;
      }
      .rr-rapid-section h6 {
        margin: 0 0 8px 0;
        font-size: 14px;
        font-weight: 700;
        color: #29435d;
      }
      .rr-rapid-section .form-label {
        margin-bottom: 4px;
      }
      .rr-compact-help {
        color: #6c757d;
        font-size: 12px;
        line-height: 17px;
      }
      .rr-pna-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
      }
      .rr-pna-grid .rr-pna-panel:only-child {
        grid-column: 1 / -1;
      }
      .rr-pna-panel {
        border: 1px solid #e3e8ef;
        background: #f8fafc;
        padding: 10px;
        min-height: 104px;
      }
      .rr-pna-panel-title {
        font-weight: 700;
        color: #394b5e;
        margin-bottom: 7px;
      }
      .rr-inline-options {
        display: flex;
        flex-wrap: wrap;
        gap: 10px 18px;
        align-items: center;
      }
      .rr-inline-options .form-check {
        margin-bottom: 0;
      }
      @media (max-width: 991.98px) {
        .rr-modal-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .rr-pna-grid { grid-template-columns: 1fr; }
      }
    </style>

    <div class="rr-modal-summary">
      <div class="rr-summary-tile"><strong>${counts.total}</strong><span>selected</span></div>
      <div class="rr-summary-tile"><strong>${counts.initial}</strong><span>initial</span></div>
      <div class="rr-summary-tile"><strong>${counts.standard}</strong><span>normal clone</span></div>
      <div class="rr-summary-tile"><strong>${counts.pnaPrior}</strong><span>PNA with prior</span></div>
      <div class="rr-summary-tile"><strong>${counts.pnaInitial}</strong><span>PNA only</span></div>
    </div>
    <div class="text-end mb-2">
      <button type="button" class="btn btn-secondary btn-sm" onclick="rrRapidClassificationModal()">
        <i class="fad fa-list"></i> View item breakdown
      </button>
    </div>

    ${needInitialType ? `
      <div class="rr-rapid-section">
        <h6>Initial reports</h6>
        <label class="form-label">Report type for never-reported items${counts.pnaInitial > 0 ? ', and PNA-only items if selected below' : ''}</label>
        <select id="rr_initial_examType" class="form-select">
          <option value="">SELECT FORMTYPE</option>
         ${RR.allowedReptypes.map(o => `<option value="${o.id}">${o.label} - ${o.type}</option>`).join('')}
        </select>
        <div class="rr-compact-help mt-2">
          Applies automatically to <b>${counts.initial}</b> item(s) with no previous report.
        </div>
      </div>
    ` : ''}

    ${(counts.pnaPrior > 0 || counts.pnaInitial > 0) ? `
      <div class="rr-rapid-section">
        <h6>PNA handling</h6>

        <div class="rr-pna-grid">
          ${pnaPriorPanel}
          ${pnaInitialPanel}
        </div>

        <label class="form-label mt-3">PNA reason</label>
        <textarea id="rr_pna_reason" class="form-control" rows="2">Item not presented for examination.</textarea>
      </div>
    ` : ''}

    <div class="rr-rapid-section">
      <h6>Clone text</h6>
      <textarea id="rr_note_text" class="form-control" rows="2" placeholder="Enter text"></textarea>
      <div class="rr-inline-options mt-2">
        <div class="form-check">
          <input class="form-check-input" type="checkbox" id="rr_note_apply">
          <label class="form-check-label" for="rr_note_apply">Overwrite existing text on all cloned reports</label>
        </div>
        <div class="form-check">
          <input class="form-check-input" type="radio" name="rr_note_type" id="rr_note_type_obs" value="observation">
          <label class="form-check-label " for="rr_note_type_obs">Observation (sets result to OBS)</label>
        </div>
        <div class="form-check">
          <input class="form-check-input" type="radio" name="rr_note_type" id="rr_note_type_rec" value="recommendation">
          <label class="form-check-label" for="rr_note_type_rec">Recommendation (keeps original result)</label>
        </div>
      </div>
      <div class="rr-compact-help mt-1">If text is entered, choose Observation or Recommendation and confirm overwrite.</div>
    </div>

    <div class="rr-rapid-section">
      <h6>Run settings</h6>
      <div class="row g-3">
        <div class="col-12 col-md-4">
          <div class="w-100 date-picker" data-date-type="open" data-mdb-toggle-button="false" data-format="dd-mm-yyyy">
            <label class="form-label">Date of examination</label>
            <input type="text" id="rr_date" class="form-control" placeholder="Examination date" value="<?= date('d-m-Y') ?>" data-mdb-confirmDateOnSelect data-mdb-toggle="datepicker">
          </div>
        </div>

        <div class="col-12 col-md-4">
          <?php if (($_SESSION['usertype'] ?? '') === 'surveyor') { ?>
            <label class="form-label">Surveyor</label>
            <input type="hidden" id="rr_surveyor" value="<?= (int)($_SESSION['userid'] ?? 0) ?>">
            <div class="form-control bg-light"><?= addslashes(rr_getSurveyorName((int)($_SESSION['userid'] ?? 0))) ?></div>
          <?php } else { ?>
            <label class="form-label">Surveyor</label>
            <div data-mdb-select-init>
              <?= listSurveyor('', 'rr_surveyor', 'select') ?>
            </div>
          <?php } ?>
        </div>

        <div class="col-12 col-md-4">
          <label class="form-label">PDF options</label>
          <div class="rr-inline-options">
            <div class="form-check form-switch">
              <input class="form-check-input" type="checkbox" id="rr_image_add">
              <label class="form-check-label" for="rr_image_add">Include Images</label>
            </div>
            <div class="form-check form-switch">
              <input class="form-check-input" type="checkbox" id="rr_tag_add">
              <label class="form-check-label" for="rr_tag_add">Include Tag</label>
            </div>
          </div>
        </div>
      </div>

      <div class="form-check mt-3">
        <input class="form-check-input" type="checkbox" id="rr_confirm">
        <label class="form-check-label" for="rr_confirm">I confirm all selected items have been inspected to statutory requirements</label>
      </div>
    </div>
  </div>

  <div id="rrRapidProcess" style="display:none">
    <div class="text-center p-4">
      <h3 class="mb-2"><i class="fad fa-spinner fa-spin"></i> Registering inspections…</h3>
      <div class="small text-muted">Do not close this window.</div>
    </div>
  </div>`;

    loadModalContent(html, 'rapidBox', 'modal-xl', 1060, 'true', 'Rapid Reporting', 'cancelConfirm', () => rrRunRapid(
        groups));

    setTimeout(() => {
        const modalEl = document.getElementById('rapidBox');
        rrInitDatepickers(modalEl);
        rrInitSurveyorSelect(modalEl);

        // --- ADD THIS BLOCK (radio disabled unless overwrite checked) ---
        const applyCb = modalEl.querySelector('#rr_note_apply');
        const noteRadios = modalEl.querySelectorAll('input[type="radio"][name="rr_note_type"]');

        if (applyCb && noteRadios.length) {
            const setNoteTypeState = () => {
                const enabled = !!applyCb.checked;
                noteRadios.forEach(r => {
                    r.disabled = !enabled;
                    if (!enabled) r.checked = false; // ensures no selection when disabled
                });
            };

            applyCb.addEventListener('change', setNoteTypeState);
            setNoteTypeState(); // initialise on open
        }
        // --- END BLOCK ---

    }, 350);
}

async function rrRunRapid(groups) {
    const confirm = document.getElementById('rr_confirm');
    if (confirm && !confirm.checked) {
        showResponse('warning', 'Please confirm inspection before proceeding');
        return;
    }

    const date = (document.getElementById('rr_date') || {}).value || '';
    const surveyor = (document.getElementById('rr_surveyor') || {}).value || '';

    if (!date || !surveyor || surveyor === 'NULL') {
        showResponse('warning', 'You must set a DATE and SURVEYOR before proceeding');
        return;
    }

    const initialExamTypeEl = document.getElementById('rr_initial_examType');
    const initialExamType = initialExamTypeEl ? (initialExamTypeEl.value || '') : '';

    const pnaInitialModeEl = document.querySelector('input[name="rr_pna_initial_mode"]:checked');
    const pnaInitialMode = pnaInitialModeEl ? pnaInitialModeEl.value : 'pna';

    const needsInitialChoice = (groups.initialItems.length > 0) ||
        (groups.pnaInitialItems.length > 0 && pnaInitialMode === 'initial');
    if (needsInitialChoice && !initialExamType) {
        showResponse('warning', 'You must select an initial report type (FORMTYPE)');
        if (initialExamTypeEl) initialExamTypeEl.focus();
        return;
    }

    const pnaModeEl = document.querySelector('input[name="rr_pna_mode"]:checked');
    const pnaMode = pnaModeEl ? pnaModeEl.value : '';
    const pnaReason = (document.getElementById('rr_pna_reason') || {}).value ||
        'Item not presented for examination.';

    const noteText = (document.getElementById('rr_note_text') || {}).value || '';
    const noteApply = !!(document.getElementById('rr_note_apply') && document.getElementById('rr_note_apply')
        .checked);
    const noteTypeEl = document.querySelector('input[name="rr_note_type"]:checked');
    const noteType = noteTypeEl ? noteTypeEl.value : '';
    const imageMode = !!(document.getElementById('rr_image_add') && document.getElementById('rr_image_add')
        .checked);
    const tagMode = !!(document.getElementById('rr_tag_add') && document.getElementById('rr_tag_add').checked);

    const noteTrim = String(noteText).trim();
    const noteHasText = (noteTrim !== '' && noteTrim.toLowerCase() !== 'none');

    if (noteHasText) {
        if (!noteApply || !noteType) {
            showResponse('warning',
                'To apply text you must confirm overwrite and select Observation or Recommendation');
            return;
        }
    }

    const start = document.getElementById('rrRapidStart');
    const proc = document.getElementById('rrRapidProcess');
    if (start) start.style.display = 'none';
    if (proc) proc.style.display = 'block';

    const body = new URLSearchParams();
    body.set('clientnumber', String(RR.clientnumber));
    body.set('chain', String(RR.chainId || ''));
    body.set('date', String(date));
    body.set('surveyor', String(surveyor));
    body.set('initial_examType', String(initialExamType));
    body.set('pna_mode', String(pnaMode));
    body.set('pna_initial_mode', String(pnaInitialMode));
    body.set('pna_reason', String(pnaReason));
    body.set('note_text', noteHasText ? noteTrim : '');
    body.set('note_apply', noteHasText && noteApply ? '1' : '0');
    body.set('note_type', noteHasText ? String(noteType) : '');
    body.set('imageMode', imageMode ? '1' : '0');
    body.set('tagMode', tagMode ? '1' : '0');
    body.set('imageset', imageMode ? '1' : '0');
    body.set('tagmode', tagMode ? '1' : '0');
    body.set('groups', JSON.stringify(groups));
    body.set('tenant', TENANT_URL);

    try {
        const res = await fetch(`${ROOT_URL}/functions/rapidrepProcess.php`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body
        });

        const txt = (await res.text()).trim();
        if (!txt.startsWith('success')) {
            showResponse('danger', txt || 'Rapid process failed');
            if (start) start.style.display = 'block';
            if (proc) proc.style.display = 'none';
            return;
        }

        const responseParts = txt.split('|');
        if (responseParts.length >= 3) {
            try {
                const pdfPayload = JSON.parse(decodeURIComponent(responseParts.slice(2).join('|')));
                if (pdfPayload && Array.isArray(pdfPayload.reports)) {
                    for (const report of pdfPayload.reports) {
                        const rep = Number(report.rep || 0);
                        const item = Number(report.item || 0);
                        if (!rep || !item) continue;

                        const genParams = new URLSearchParams({
                            orientation: '1',
                            imageMode: String(pdfPayload.imageMode || 0),
                            tagMode: String(pdfPayload.tagMode || 0),
                            imageset: String(pdfPayload.imageMode || 0),
                            tagmode: String(pdfPayload.tagMode || 0),
                            clientnumber: String(RR.clientnumber),
                            repnumber: String(rep),
                            items: String(item),
                            tenant: TENANT_URL
                        });

                        await fetch(`${ROOT_URL}/functions/generators/genPDF2.php`, {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/x-www-form-urlencoded'
                            },
                            body: genParams.toString()
                        });
                    }
                }
            } catch (e) {
                showResponse('danger', 'Rapid reports were created but PDF generation options failed');
                if (start) start.style.display = 'block';
                if (proc) proc.style.display = 'none';
                return;
            }
        }

        window.location.href =
            `index.php?t=includes/master&p=linked.php&clientnumber=<?= $clientnumber ?>&itemnumber=<?= $seedItem ?>`;
    } catch (e) {
        showResponse('danger', 'Network error while processing RapidRep');
        if (start) start.style.display = 'block';
        if (proc) proc.style.display = 'none';
    }
}

function repidRewind() {
    const content = `
    <div class="row mb-3">
      <div class="col-12 lead text-center">Are you sure you wish to restore the <?= (int)$storedCount ?> reports stored on <?= $storedEntry ? date('d-m-Y', (int)$storedEntry['date']) : '' ?>?</div>
      <div class="col-12 text-center">This cannot be undone</div>
    </div>`;
    loadModalContent(content, "popupBox", "modal-md", 1060, "true", "Rapid Rewind", "cancelConfirm", rewind);
}

function rewind() {
    killModal('popupBox');

    const items = <?= $storedEntry ? json_encode((string)$storedEntry['reps']) : "''" ?>;
    const xhr = new XMLHttpRequest();
    xhr.open('POST', `${ROOT_URL}/functions/rapidRewind.php`, true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

    xhr.onload = function() {
        const t = (xhr.responseText || '').trim();
        if (xhr.status === 200 && t === 'done') {
            window.location.href =
                "index.php?t=includes/master&p=linked.php&clientnumber=<?= $clientnumber ?>&itemnumber=<?= $seedItem ?>";
        } else {
            showResponse('danger', t || 'Rewind failed');
        }
    };

    xhr.send('payload=' + encodeURIComponent(items) +
        '&clientnumber=<?= $clientnumber ?>' +
        '&entry=<?= $storedEntry ? (int)$storedEntry['id'] : 0 ?>' +
        '&tenant=' + encodeURIComponent(TENANT_URL));
}

async function rrMassPNA() {
    const selectedRows = rrGetSelectedRows();

    if (selectedRows.length < 1) {
        showResponse('warning', 'Select at least 1 item for PNA');
        return;
    }

    const items = selectedRows
        .map(tr => Number(tr.dataset.itemnumber || 0))
        .filter(id => id > 0)
        .join(',');

    if (!items) {
        showResponse('warning', 'No valid items selected');
        return;
    }

    const postData = new URLSearchParams({
        clientnumber: '<?= (int)$clientnumber ?>',
        tenant: TENANT_URL,
        items
    });

    try {
        const response = await fetch(`${ROOT_URL}/includes/mass/massPna.php`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: postData.toString()
        });

        if (!response.ok) {
            throw new Error(`Mass PNA modal failed with status ${response.status}`);
        }

        const modalHtml = await response.text();
        loadModalContent(
            modalHtml,
            'pnaBoxes',
            'modal-xxl',
            1060,
            'true',
            'Mass PNA items',
            'cancelConfirm',
            'processPna'
        );
    } catch (error) {
        console.error('Mass PNA modal request failed:', error);
        showResponse('danger', 'There was an error loading the Mass PNA window.');
    }
}

document.addEventListener('DOMContentLoaded', () => {
    const loading = document.getElementById('loadingObject');
    const data = document.getElementById('data');
    if (loading) loading.style.display = 'none';
    if (data) data.style.display = 'block';

    const rrTable = document.getElementById('rrTable');

    // ---------- COLUMN SORTING (ASC/DESC) ----------
    function rrParseDMY(value) {
        const v = String(value || '').trim();
        if (!v || v.toUpperCase() === 'NDS') return null;
        const m = v.match(/^(\d{2})-(\d{2})-(\d{4})$/);
        if (!m) return null;
        const dd = parseInt(m[1], 10),
            mm = parseInt(m[2], 10),
            yyyy = parseInt(m[3], 10);
        if (!dd || !mm || !yyyy) return null;
        return new Date(yyyy, mm - 1, dd).getTime();
    }

    function rrCellText(mainRow, selector) {
        const td = mainRow.querySelector(selector);
        return td ? td.textContent.trim() : '';
    }

    function rrGetSortValue(mainRow, col) {
        switch (col) {
            case 'desc':
                return rrCellText(mainRow, 'td.col-desc');
            case 'plant':
                return rrCellText(mainRow, 'td.col-plant');
            case 'serial':
                return rrCellText(mainRow, 'td.col-serial');
            case 'location':
                return rrCellText(mainRow, 'td.col-location');
            case 'subloc':
                return rrCellText(mainRow, 'td.col-subloc');
            case 'postcode':
                return rrCellText(mainRow, 'td.col-postcode');
            case 'result':
                return String(mainRow.dataset.lastResult || rrCellText(mainRow, 'td.col-result')).trim();
            case 'due': {
                const t = rrParseDMY(rrCellText(mainRow, 'td.col-due'));
                return (t === null) ? Number.POSITIVE_INFINITY : t;
            }
            default:
                return '';
        }
    }

    function rrCompare(a, b, dir, numeric = false) {
        const mult = (dir === 'DESC') ? -1 : 1;

        if (numeric) {
            const na = (typeof a === 'number') ? a : Number(a);
            const nb = (typeof b === 'number') ? b : Number(b);
            if (isNaN(na) && isNaN(nb)) return 0;
            if (isNaN(na)) return 1 * mult;
            if (isNaN(nb)) return -1 * mult;
            return (na - nb) * mult;
        }

        const sa = String(a ?? '').toLowerCase();
        const sb = String(b ?? '').toLowerCase();
        if (sa < sb) return -1 * mult;
        if (sa > sb) return 1 * mult;
        return 0;
    }

    function rrSortTableBy(col, dir) {
        if (!rrTable) return;
        const tbody = rrTable.querySelector('tbody');
        if (!tbody) return;

        const mains = Array.from(tbody.querySelectorAll('tr.rr-main-row'));
        const blocks = mains.map(mainRow => {
            const item = mainRow.getAttribute('data-itemnumber');
            const detailRow = document.getElementById('rr_detail_' + item);
            return {
                mainRow,
                detailRow,
                value: rrGetSortValue(mainRow, col)
            };
        });

        const numericCols = new Set(['due']);
        blocks.sort((x, y) => rrCompare(x.value, y.value, dir, numericCols.has(col)));

        const frag = document.createDocumentFragment();
        blocks.forEach(b => {
            frag.appendChild(b.mainRow);
            if (b.detailRow) frag.appendChild(b.detailRow);
        });

        tbody.innerHTML = '';
        tbody.appendChild(frag);

        // keep selected row styling in sync after DOM reorder
        rrSyncAllSelectedClasses();
    }

    function rrClearHeaderSortState() {
        rrTable.querySelectorAll('th.rr-sortable').forEach(th => {
            th.classList.remove('rr-sorted-asc', 'rr-sorted-desc');
        });
    }

    function rrInitHeaderSorting() {
        if (!rrTable) return;
        rrTable.querySelectorAll('th.rr-sortable').forEach(th => {
            th.addEventListener('click', () => {
                const col = th.getAttribute('data-sort-col');
                if (!col) return;

                const currentlyAsc = th.classList.contains('rr-sorted-asc');
                const dir = currentlyAsc ? 'DESC' : 'ASC';

                rrClearHeaderSortState();
                th.classList.add(dir === 'ASC' ? 'rr-sorted-asc' : 'rr-sorted-desc');

                rrSortTableBy(col, dir);
            });
        });
    }

    rrInitHeaderSorting();
    // ---------- /COLUMN SORTING ----------



    function rrSetDetailColspan(itemId) {
        const detailRow = document.getElementById('rr_detail_' + itemId);
        if (!detailRow) return;

        const td = detailRow.querySelector('td');
        if (!td) return;

        const ths = rrTable ? rrTable.querySelectorAll('thead th') : [];
        let visibleCount = 0;

        ths.forEach((th) => {
            const cs = window.getComputedStyle(th);
            if (cs.display === 'none') return;
            const rect = th.getBoundingClientRect();
            if (rect.width <= 0) return;
            visibleCount++;
        });

        // Fallback: if layout timing gives 0 widths, use total header count.
        if (visibleCount <= 0) visibleCount = ths.length || 1;

        td.colSpan = visibleCount;
    }

    document.body.addEventListener('click', (e) => {
        const btn = e.target.closest('.rr-detail-toggle');
        if (!btn) return;
        const id = btn.dataset.item;
        const row = document.getElementById('rr_detail_' + id);
        if (!row) return;

        const willOpen = (row.style.display === 'none' || !row.style.display);
        if (willOpen) rrSetDetailColspan(id);
        row.style.display = willOpen ? 'table-row' : 'none';
    });

    window.addEventListener('resize', () => {
        document.querySelectorAll('#rrTable tbody tr.rr-detail-row').forEach((r) => {
            if (r.style.display === 'table-row') {
                const id = (r.id || '').replace('rr_detail_', '');
                if (id) rrSetDetailColspan(id);
            }
        });
    });

    document.body.addEventListener('click', (e) => {
        const label = e.target.closest('.rr-row-label');
        if (!label) return;
        const forId = label.getAttribute('for');
        if (!forId) return;
        const cb = document.getElementById(forId);
        if (!cb || cb.disabled) return;
        cb.checked = !cb.checked;
        rrUpdateSelectedCount();
    });

    document.body.addEventListener('change', (e) => {
        if (e.target && e.target.classList.contains('rr-check')) rrUpdateSelectedCount();
    });

    const selAll = document.getElementById('rrSelectAllBtn');
    if (selAll) selAll.addEventListener('click', rrSelectAll);

    const deselAll = document.getElementById('rrDeselectAllBtn');
    if (deselAll) deselAll.addEventListener('click', rrDeselectAll);

    const clear = document.getElementById('rrClearBtn');
    if (clear) clear.addEventListener('click', rrClearAll);

    const rapid1 = document.getElementById('rrRapidBtn');
    if (rapid1) rapid1.addEventListener('click', rrRapidModal);

    const rapid2 = document.getElementById('rrRapidBtn2');
    if (rapid2) rapid2.addEventListener('click', rrRapidModal);

    const pna1 = document.getElementById('rrPnaBtn');
    if (pna1) pna1.addEventListener('click', rrMassPNA);

    const pna2 = document.getElementById('rrPnaBtn2');
    if (pna2) pna2.addEventListener('click', rrMassPNA);

    const toggleAll = document.getElementById('rrToggleAllDetails');
    if (toggleAll) {
        toggleAll.addEventListener('click', () => {
            const anyHidden = !!document.querySelector(
                '#rrTable tbody tr.rr-detail-row[style*="display:none"]');
            document.querySelectorAll('#rrTable tbody tr.rr-detail-row').forEach((r) => {
                if (anyHidden) {
                    const id = (r.id || '').replace('rr_detail_', '');
                    if (id) rrSetDetailColspan(id);
                    r.style.display = 'table-row';
                } else {
                    r.style.display = 'none';
                }
            });
        });
    }

    rrUpdateSelectedCount();

    rrTable.querySelector('tbody').addEventListener('click', function(event) {
        var target = event.target.closest('.formButton, .transferButton, .archiveButton');
        if (target) {
            var href = target.getAttribute('data-href');
            var values = target.getAttribute('data-values');
            var title = target.getAttribute('data-mdb-original-title');
            var dest = encodeURI(href + "?data=" + values +
                "&tenant=<?= addslashes($systemUser ?? '') ?>");
            loadModalContent(dest, "transferBox", "modal-xl", 1060, "true", title, "close");
        }
    });
});
</script>
