<?php
if (file_exists('../../../' . ($_REQUEST['tenant'] ?? '') . '/config.php')) {
    require_once('../../../' . $_REQUEST['tenant'] . '/config.php');
}
if (file_exists('/config.php')) {
    require_once('/config.php');
}

if (file_exists(__DIR__ . '/../../functions/logging.php')) {
    require_once __DIR__ . '/../../functions/logging.php';
}

function reportsOutstandingH($value): string
{
    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
}

function reportsOutstandingReviewTableAvailable(): bool
{
    if (empty($GLOBALS['con']) || !($GLOBALS['con'] instanceof mysqli)) {
        return false;
    }

    $stmt = $GLOBALS['con']->prepare("SELECT `id` FROM `report_review_actions` LIMIT 1");
    if (!$stmt) {
        return false;
    }
    $ok = $stmt->execute();
    $stmt->close();
    return $ok;
}

function reportsOutstandingFetchReviewActions(int $clientnumber, array $repnumbers): array
{
    $repnumbers = array_values(array_unique(array_filter(array_map('strval', $repnumbers))));
    if ($clientnumber <= 0 || empty($repnumbers)) {
        return [];
    }

    $ph = implode(',', array_fill(0, count($repnumbers), '?'));
    $types = 'i' . str_repeat('s', count($repnumbers));
    $params = array_merge([$clientnumber], $repnumbers);
    $stmt = $GLOBALS['con']->prepare("
        SELECT `id`, `repitem`, `repnumber`, `itemnumber`, `surveyor_id`, `status`, `admin_note`, `surveyor_response`, `created_at`, `updated_at`
        FROM `report_review_actions`
        WHERE `clientnumber` = ? AND `repnumber` IN ($ph)
    ");
    if (!$stmt) {
        return [];
    }
    $stmt->bind_param($types, ...$params);
    if (!$stmt->execute()) {
        $stmt->close();
        return [];
    }
    $res = $stmt->get_result();
    $actions = [];
    while ($row = $res->fetch_assoc()) {
        $actions[(int)$row['repitem']] = $row;
    }
    $stmt->close();
    return $actions;
}

function reportsOutstandingReviewBadge(?array $action): string
{
    if (!$action) {
        return '<span class="badge bg-secondary">Not reviewed</span>';
    }

    $status = (string)($action['status'] ?? '');
    $labels = [
        'ready' => ['Ready to send', 'bg-success'],
        'pending' => ['Correction pending', 'bg-warning text-dark'],
        'responded' => ['Surveyor responded', 'bg-danger text-white'],
        'complete' => ['Action complete', 'bg-primary'],
    ];
    $label = $labels[$status] ?? [ucfirst($status ?: 'Unknown'), 'bg-secondary'];
    return '<span class="badge ' . reportsOutstandingH($label[1]) . '">' . reportsOutstandingH($label[0]) . '</span>';
}

function reportsOutstandingResultBadge($result): string
{
    $clean = trim((string)$result);
    if ($clean === '') {
        return '<span class="badge bg-light text-dark">N/E</span>';
    }

    $upper = strtoupper($clean);
    $class = 'bg-secondary';
    if (in_array($upper, ['PASS', 'SATISFACTORY', 'POBS'], true)) {
        $class = 'success-color-dark';
    } elseif (in_array($upper, ['FAIL', 'UNSATISFACTORY', 'URGENT'], true)) {
        $class = 'danger-color-dark';
    } elseif ($upper === 'DEFECTS') {
        $class = 'warning-color-dark';
    } elseif ($upper === 'OBS') {
        $class = 'special-color';
    } elseif ($upper === 'PNA') {
        $class = 'stylish-color-dark';
    }

    return '<span class="badge ' . reportsOutstandingH($class) . ' text-light">' . reportsOutstandingH($clean) . '</span>';
}

if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST' && ($_POST['FUNCTION'] ?? '') === 'markAllSent') {
    header('Content-Type: application/json; charset=utf-8');

    $clientnumber = (int)($_POST['clientnumber'] ?? 0);
    $repJson = (string)($_POST['repnumbers'] ?? '[]');
    $repList = json_decode($repJson, true);

    if ($clientnumber <= 0) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'Invalid clientnumber']);
        exit;
    }
    if (!is_array($repList) || count($repList) === 0) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'No repnumbers supplied']);
        exit;
    }

    $repList = array_values(array_unique(array_filter(array_map(static function ($v) {
        $v = trim((string)$v);
        return $v === '' ? null : $v;
    }, $repList))));

    if (count($repList) === 0) {
        http_response_code(400);
        echo json_encode(['status' => 'error', 'message' => 'No valid repnumbers supplied']);
        exit;
    }

    if (!reportsOutstandingReviewTableAvailable()) {
        echo json_encode(['status' => 'warning', 'message' => 'Review tracking is not available, so no reports can be marked as ready to send.']);
        exit;
    }

    $now = time();

    $ph = implode(',', array_fill(0, count($repList), '?'));
    $types = 'i' . str_repeat('s', count($repList));
    $params = array_merge([$clientnumber], $repList);

    $sqlDetails = "
        SELECT
            a.`repitem`,
            a.`repnumber`,
            a.`itemnumber`,
            a.`insdate`,
            i.`desc` AS item_name,
            i.`plantnumber`,
            i.`serialnumber`,
            i.`subloc`,
            l.`locname`
        FROM `reportitems` a
        INNER JOIN `report_review_actions` rra ON a.`repitem` = rra.`repitem` AND rra.`status` = 'ready'
        LEFT JOIN `itemdetails` i ON a.`itemnumber` = i.`itemnumber`
        LEFT JOIN `locations` l ON i.`locnumber` = l.`locnumber`
        WHERE a.`clientnumber` = ? AND a.`delivery` = 0 AND a.`repnumber` IN ($ph)
        ORDER BY ABS(a.`repitem`) DESC
    ";
    $stmt = $GLOBALS['con']->prepare($sqlDetails);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $rs = $stmt->get_result();
    $reportDetails = $rs ? $rs->fetch_all(MYSQLI_ASSOC) : [];
    $stmt->close();
    $count = count($reportDetails);

    if ($count <= 0) {
        echo json_encode(['status' => 'warning', 'message' => 'No reports are marked ready to send.']);
        exit;
    }

    $readyRepList = array_values(array_unique(array_map(static function ($row) {
        return (string)($row['repnumber'] ?? '');
    }, $reportDetails)));
    $readyPh = implode(',', array_fill(0, count($readyRepList), '?'));

    $sqlUpd = "UPDATE `reportitems` SET `delivery` = ? WHERE `clientnumber` = ? AND `delivery` = 0 AND `repnumber` IN ($readyPh)";
    $stmt = $GLOBALS['con']->prepare($sqlUpd);

    $types2 = 'ii' . str_repeat('s', count($readyRepList));
    $params2 = array_merge([$now, $clientnumber], $readyRepList);
    $stmt->bind_param($types2, ...$params2);
    $stmt->execute();
    $updated = (int)$stmt->affected_rows;
    $stmt->close();

    if ($updated > 0) {
        $deleteTypes = 'i' . str_repeat('s', count($readyRepList));
        $deleteParams = array_merge([$clientnumber], $readyRepList);
        $stmt = $GLOBALS['con']->prepare("DELETE FROM `report_review_actions` WHERE `clientnumber` = ? AND `repnumber` IN ($readyPh)");
        $stmt->bind_param($deleteTypes, ...$deleteParams);
        $stmt->execute();
        $stmt->close();
    }

    if ($updated > 0 && function_exists('enrep_log')) {
        $itemLines = [];
        foreach ($reportDetails as $detail) {
            $location = trim((string)($detail['locname'] ?? '') . ' ' . (string)($detail['subloc'] ?? ''));
            $itemLines[] = 'Report ' . (string)$detail['repnumber']
                . ' - Item ' . (int)$detail['itemnumber']
                . ' - ' . trim((string)($detail['item_name'] ?? ''))
                . ' - Plant ' . trim((string)($detail['plantnumber'] ?? ''))
                . ' - Serial ' . trim((string)($detail['serialnumber'] ?? ''))
                . ($location !== '' ? ' - ' . $location : '');
        }
        enrep_log('delivery', 'marked_all_sent', 'Marked ' . $updated . ' outstanding report item(s) as sent for ' . getClientName($clientnumber, 'name') . ".\n\nItems:\n" . implode("\n", $itemLines), [
            'entity_type' => 'reportitems',
            'entity_id' => (string)$clientnumber,
            'clientnumber' => $clientnumber,
            'subject' => 'Reports marked as sent',
            'repnumbers' => $repList,
            'items' => $reportDetails,
        ]);
    }

    echo json_encode(['status' => 'success', 'updated' => $updated, 'ts' => $now]);
    exit;
}
?>

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

    #datatable {
        table-layout: fixed
    }

    #datatable.table-sm>:not(caption)>*>* {
        padding: .25rem .35rem
    }

    #datatable td.nowrap,
    #datatable th.nowrap {
        white-space: nowrap
    }

    #datatable td.ellipsis,
    #datatable th.ellipsis {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap
    }

    #datatable th[data-sort-key] {
        cursor: pointer;
        position: relative;
        padding-right: 1.2rem
    }

    #datatable th[data-sort-key]::after {
        color: rgba(255, 255, 255, .45);
        content: "\f0dc";
        font-family: "Font Awesome 6 Duotone", "Font Awesome 5 Duotone", "Font Awesome 6 Pro", "Font Awesome 5 Pro", "Font Awesome 6 Free";
        font-weight: 900;
        position: absolute;
        right: .35rem
    }

    #datatable th[data-sort-key].outstanding-sort-active::after {
        color: #fff
    }

    #datatable th[data-sort-key].outstanding-sort-asc::after {
        content: "\f0de"
    }

    #datatable th[data-sort-key].outstanding-sort-desc::after {
        content: "\f0dd"
    }

    #datatable col.col-ready {
        width: 4%
    }

    #datatable col.col-item {
        width: 5%
    }

    #datatable col.col-report {
        width: 8%
    }

    #datatable col.col-desc {
        width: 14%
    }

    #datatable col.col-plant {
        width: 7%
    }

    #datatable col.col-serial {
        width: 7%
    }

    #datatable col.col-location {
        width: 11%
    }

    #datatable col.col-exam {
        width: 8%
    }

    #datatable col.col-result {
        width: 7%
    }

    #datatable col.col-validation {
        width: 10%
    }

    #datatable col.col-actions {
        width: 15%
    }

    .status_colour {
        width: 18px;
        max-width: 18px;
        padding: 0 !important
    }

    .report-result-cell {
        text-align: left
    }

    .report-result-cell .badge {
        font-size: .78rem
    }

    .review-status-cell .badge {
        font-size: .78rem
    }

    .ready-check {
        color: #14a44d;
        font-size: 1rem
    }

    .ready-check-empty {
        display: inline-block;
        height: 1rem;
        width: 1rem
    }

    .ready-status-cell {
        text-align: center
    }

    .ready-status-cell .form-check-input {
        cursor: pointer;
        margin: 0
    }

    #datatable td.col-actions .btn {
        min-width: 1.75rem;
        padding: .2rem .4rem
    }

    #datatable tbody tr>td {
        background: #ffffff
    }

    #datatable tbody tr.asset-row-striped>td {
        background: #f8fafc
    }

    #datatable tbody tr:hover>td {
        background: #0055A6 !important;
        color: #ffffff !important
    }

    .outstanding-table-wrap {
        border: 1px solid #dfe5eb;
        border-radius: 6px;
        overflow: hidden
    }

    .outstanding-search-bar {
        align-items: end;
        gap: .5rem
    }

    .outstanding-search-actions {
        align-items: end;
        gap: .5rem
    }

    .outstanding-search-bar .form-control {
        max-width: 420px
    }

    .outstanding-mobile-sort {
        max-width: 240px
    }

    #outstandingEmptyState {
        display: none
    }

    .outstanding-ready-helper {
        align-items: flex-start;
        display: flex;
        gap: .65rem;
        color: #fff
    }

    .outstanding-ready-helper i {
        font-size: 1.15rem;
        margin-top: .15rem;
        color: #fff
    }

    .surveyor-responses-summary {
        border: 1px solid #f2c94c;
        border-left: 5px solid #f2c94c;
        border-radius: 6px;
        display: none;
        max-height: 9.5rem;
        overflow-y: auto
    }

    .surveyor-responses-summary .response-list {
        display: grid;
        gap: .35rem
    }

    .surveyor-response-jump {
        align-items: center;
        background: #fff;
        border: 1px solid #e0e6ec;
        border-radius: 5px;
        color: #263238;
        display: grid;
        gap: .15rem .5rem;
        grid-template-columns: auto minmax(0, 1fr) auto;
        padding: .35rem .5rem;
        text-align: left;
        width: 100%
    }

    .surveyor-response-jump:hover,
    .surveyor-response-jump:focus {
        background: #f8fbff;
        border-color: #0055A6;
        color: #0055A6
    }

    .surveyor-response-jump .response-meta {
        font-weight: 700;
        white-space: nowrap
    }

    .surveyor-response-jump .response-preview {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap
    }

    #datatable tbody tr.outstanding-row-highlight>td {
        animation: outstandingResponseHighlight 2.8s ease;
        background: #fff3cd !important;
        color: #1f2b36 !important
    }

    #datatable tbody tr.outstanding-row-highlight {
        box-shadow: inset 0 0 0 2px #f2c94c
    }

    @keyframes outstandingResponseHighlight {
        0% {
            background: #ffe08a
        }

        100% {
            background: #fff3cd
        }
    }

    .review-contact-grid {
        display: grid;
        grid-template-columns: 120px minmax(0, 1fr);
        gap: .35rem .75rem
    }

    .review-contact-grid dt {
        color: #66717d;
        font-weight: 700;
        margin: 0
    }

    .review-contact-grid dd {
        margin: 0;
        min-width: 0;
        overflow-wrap: anywhere
    }

    @media (max-width: 991px) {
        .outstanding-table-wrap {
            border: 0;
            overflow: visible
        }

        .outstanding-search-bar {
            align-items: flex-end
        }

        .outstanding-search-bar>.outstanding-search-actions,
        .outstanding-search-bar>.outstanding-mobile-sort-wrap {
            flex: 1 1 calc(50% - .25rem);
            max-width: calc(50% - .25rem);
            width: calc(50% - .25rem)
        }

        .outstanding-search-actions>div:first-child {
            flex: 1 1 100%;
            width: 100%
        }

        .outstanding-search-bar>.text-muted {
            flex: 1 0 100%;
            text-align: right;
            width: 100%
        }

        .outstanding-search-bar .form-control,
        .outstanding-mobile-sort {
            max-width: none;
            width: 100%
        }

        #datatable {
            border-collapse: separate;
            border-spacing: 0 .75rem;
            table-layout: auto
        }

        #datatable colgroup,
        #datatable thead {
            display: none
        }

        #datatable tbody,
        #datatable td {
            display: block
        }

        #datatable tr {
            background: #fff;
            border: 1px solid #dfe5eb;
            border-left: 5px solid #294766;
            border-radius: 6px;
            box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
            display: grid;
            grid-template-columns: repeat(3, minmax(0, 1fr));
            overflow: hidden
        }

        #datatable tr.asset-row-striped,
        #datatable tr.asset-row-striped>td {
            background: #f8fafc
        }

        #datatable tr:hover,
        #datatable tr:hover>td {
            background: #0055A6 !important;
            color: #ffffff !important
        }

        #datatable.table-sm>:not(caption)>*>* {
            padding: .45rem .65rem
        }

        #datatable td {
            border: 0;
            border-bottom: 1px solid #eef1f4;
            border-right: 1px solid #eef1f4;
            min-width: 0;
            white-space: normal !important;
            width: auto !important
        }

        #datatable td:nth-child(3n),
        #datatable td.col-actions {
            border-right: 0
        }

        #datatable td::before {
            color: #5f6b76;
            content: attr(data-label);
            display: block;
            font-size: .72rem;
            font-weight: 700;
            line-height: 1.1;
            margin-bottom: .16rem;
            text-transform: uppercase
        }

        #datatable td.col-ready {
            order: 2
        }

        #datatable td.col-desc {
            background: #fff;
            font-size: 1rem;
            font-weight: 700;
            grid-column: 1/-1;
            order: 1
        }

        #datatable td.col-desc::before {
            display: none
        }

        #datatable td.col-item {
            order: 3
        }

        #datatable td.col-report {
            order: 4
        }

        #datatable td.col-plant {
            order: 5
        }

        #datatable td.col-serial {
            order: 6
        }

        #datatable td.col-location {
            grid-column: span 2;
            order: 7
        }

        #datatable td.col-exam {
            order: 8
        }

        #datatable td.col-result {
            order: 9
        }

        #datatable td.col-validation {
            order: 10
        }

        #datatable td.col-actions {
            border-bottom: 0;
            grid-column: 1/-1;
            order: 11;
            text-align: left !important
        }

        #datatable td.col-actions::before {
            display: none
        }

        #datatable td.col-actions .btn {
            margin-bottom: .25rem
        }

        #datatable td.report-result-cell .badge,
        #datatable td.review-status-cell .badge {
            font-size: .78rem
        }

        .surveyor-response-jump {
            grid-template-columns: minmax(0, 1fr) auto
        }

        .surveyor-response-jump .response-preview {
            grid-column: 1/-1
        }
    }

    @media (max-width: 575px) {
        #datatable tr {
            grid-template-columns: repeat(2, minmax(0, 1fr))
        }

        #datatable td:nth-child(3n) {
            border-right: 1px solid #eef1f4
        }

        #datatable td:nth-child(2n),
        #datatable td.col-actions {
            border-right: 0
        }

        #datatable td.col-desc,
        #datatable td.col-location {
            grid-column: 1/-1
        }
    }

    @media (min-width: 992px) {
        .outstanding-mobile-sort-wrap {
            display: none !important
        }
    }
</style>

<div class="row align-items-end">
    <div class="col-12 col-md-7 note note-light mb-3">

        <strong>You have <span id="counter"></span> reports outstanding for delivery.</strong>
        <span class="small">You can choose to deliver the documents individually or as a batch using the main delivery
            system.</span>

    </div>

    <?php $_SESSION['contractorNumber'];
    if (empty($_SESSION['contractorNumber'])) { ?>
        <div class="col-12 col-md-5 text-md-end">
            <a class="btn btn-success btn-sm mb-3 me-3" href="javascript:void(0)" onclick="confirmMarkSelectedReady()"
                data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                title="Mark selected reports ready to send">
                <i class="fad fa-check"></i> Mark selected ready
            </a>

            <a class="btn btn-secondary btn-sm mb-3 me-3" href="javascript:void(0)" onclick="deliverAll()"
                data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                title="Deliver reports marked ready to send">
                <i class="fad fa-share-square"></i> Deliver ready reports
            </a>

            <a class="btn btn-info btn-sm mb-3" href="javascript:void(0)" onclick="confirmMarkAllSent()"
                data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                title="Mark reports ready to send as sent">
                <i class="fad fa-check-double"></i> Mark ready as sent
            </a>
        </div>
    <?php } ?>
</div>

<div id="surveyorResponsesSummary" class="surveyor-responses-summary alert alert-warning py-2 mb-3" aria-live="polite">
    <div class="d-flex align-items-center justify-content-between gap-2 mb-2">
        <strong><i class="fad fa-reply me-1" aria-hidden="true"></i><span id="surveyorResponsesCount">0</span> surveyor response(s)</strong>
        <span class="small text-muted">Click a response to jump to its report row.</span>
    </div>
    <div id="surveyorResponsesList" class="response-list"></div>
</div>

<div class="alert alert-info py-2 outstanding-ready-helper">
    <i class="fad fa-info-circle" aria-hidden="true"></i>
    <div>
        <strong>Ready-to-send control:</strong>
        Batch actions only include reports marked <strong>Ready to send</strong>. Reports still marked not reviewed,
        correction pending, responded, or complete stay outstanding until an admin marks them ready.
        <span class="d-block small mt-1"><strong><span id="readyCounter">0</span></strong> ready for batch delivery;
            <strong><span id="notReadyCounter">0</span></strong> will be left outstanding.</span>
    </div>
</div>

<div class="col-12 text-center">
    <div id="loadingObject">
        <h1 class="text-center"><i class="fad fa-cog fa-spin fa-3x fa-fw"
                style="--fa-primary-color:#0055A6; --fa-secondary-color:gray;"></i></h1>
        <h1>Loading Reports <br><small>Please wait</small></h1>
    </div>
</div>

<?php $reviewTableReady = reportsOutstandingReviewTableAvailable(); ?>
<?php if (!$reviewTableReady) { ?>
    <div class="alert alert-warning py-2">
        Report review tracking is waiting for the database table to be installed. Outstanding reports are still shown, but
        review actions are disabled.
    </div>
<?php } ?>

<div id="exportTitle" style="display:none">Reports Outstanding - <?= getClientName($_REQUEST['clientnumber'], 'name') ?>
    - <?= date('d-m-Y') ?></div>

<div class="col-12">
    <div class="d-flex flex-wrap justify-content-between outstanding-search-bar mb-2">
        <div class="d-flex flex-wrap outstanding-search-actions">
            <div>
                <label for="outstandingQuickSearch" class="form-label mb-1">Search</label>
                <input type="search" id="outstandingQuickSearch" class="form-control form-control-sm" autocomplete="off"
                    placeholder="Search reports">
            </div>
            <div class="d-flex flex-wrap gap-2 mb-1">
                <button type="button" class="btn btn-outline-secondary btn-sm"
                    onclick="selectAllVisibleOutstandingReports()" data-mdb-tooltip-init data-mdb-placement="top"
                    data-mdb-trigger="hover" title="Select all visible reports">
                    <i class="fad fa-list-check"></i> Select visible
                </button>
                <button type="button" class="btn btn-outline-secondary btn-sm"
                    onclick="deselectAllVisibleOutstandingReports()" data-mdb-tooltip-init data-mdb-placement="top"
                    data-mdb-trigger="hover" title="Deselect all visible reports">
                    <i class="fad fa-list"></i> Deselect visible
                </button>
            </div>
        </div>
        <div class="outstanding-mobile-sort-wrap">
            <label for="outstandingMobileSort" class="form-label mb-1">Sort</label>
            <select id="outstandingMobileSort" class="form-select form-select-sm outstanding-mobile-sort">
                <option value="">Newest report first</option>
                <option value="item:asc:number">Item A-Z</option>
                <option value="item:desc:number">Item Z-A</option>
                <option value="report:asc:number">Report A-Z</option>
                <option value="report:desc:number">Report Z-A</option>
                <option value="description:asc:text">Description A-Z</option>
                <option value="description:desc:text">Description Z-A</option>
                <option value="exam:desc:number">Exam Date newest</option>
                <option value="exam:asc:number">Exam Date oldest</option>
                <option value="result:asc:text">Result A-Z</option>
                <option value="validation:asc:text">Validation A-Z</option>
            </select>
        </div>
        <div class="text-muted small mb-1">
            Showing <b id="outstandingVisibleCount">0</b> of <b id="outstandingTotalCount">0</b>
        </div>
    </div>
    <div class="outstanding-table-wrap">
        <table id="datatable" class="table table-sm table-hover align-middle mb-0" style="display:none; width:100%">
            <colgroup>
                <col class="col-ready">
                <col class="col-item">
                <col class="col-report">
                <col class="col-desc">
                <col class="col-plant">
                <col class="col-serial">
                <col class="col-location">
                <col class="col-exam">
                <col class="col-result">
                <col class="col-validation">
                <col class="col-actions">
            </colgroup>
            <thead class="table-dark">
                <tr>
                    <th class="no-sort nowrap col-ready text-center" title="Selected / Ready"></th>
                    <th class="nowrap col-item" data-sort-key="item" data-sort-type="number">Item</th>
                    <th class="nowrap col-report" data-sort-key="report" data-sort-type="number">Report</th>
                    <th class="ellipsis col-desc" data-sort-key="description" data-sort-type="text">Item Description
                    </th>
                    <th class="nowrap col-plant" data-sort-key="plant" data-sort-type="natural">Plant</th>
                    <th class="nowrap col-serial" data-sort-key="serial" data-sort-type="natural">Serial</th>
                    <th class="ellipsis col-location" data-sort-key="location" data-sort-type="text">Location</th>
                    <th class="nowrap col-exam" data-sort-key="exam" data-sort-type="number">Exam Date</th>
                    <th class="nowrap report-result-cell col-result" data-sort-key="result" data-sort-type="text">Result
                    </th>
                    <th class="nowrap review-status-cell col-validation" data-sort-key="validation"
                        data-sort-type="text">Validation</th>
                    <th class="no-sort nowrap text-end col-actions"></th>
                </tr>
            </thead>
            <tbody>
                <?php
                unset($_SESSION['itemlist']);

                $clientnumber = (int)($_REQUEST['clientnumber'] ?? 0);

                $stmt = $GLOBALS['con']->prepare("
            SELECT
                a.clientnumber,
                a.repitem,
                a.repnumber,
                a.itemnumber,
                a.delivery,
                a.insdate,
                a.result,
                a.reptype,
                a.esname,
                s.forename AS surveyor_forename,
                s.surname AS surveyor_surname,
                s.email AS surveyor_email,
                s.phone1 AS surveyor_phone,
                s.mobile AS surveyor_mobile
            FROM reportitems a
            LEFT JOIN surveyor s ON a.esname = s.id
            WHERE a.delivery = 0 AND a.clientnumber = ?
            ORDER BY ABS(a.repitem) DESC
        ") or die(mysqli_error($GLOBALS['con']));
                $stmt->bind_param('i', $clientnumber);
                $stmt->execute();
                $items = $stmt->get_result();
                $stmt->close();
                $reportRows = $items ? $items->fetch_all(MYSQLI_ASSOC) : [];

                $itemlist = [];
                $readyItemlist = [];
                $readyRepnumbers = [];
                $repnumbers = [];
                foreach ($reportRows as $row) {
                    $repnumbers[] = (string)$row['repnumber'];
                }
                $repnumbers = array_values(array_unique($repnumbers));
                $reviewActions = $reviewTableReady ? reportsOutstandingFetchReviewActions($clientnumber, $repnumbers) : [];
                $reviewPayload = [];
                $counter = 0;

                $minDate = null;
                $maxDate = null;

                foreach ($reportRows as $list) {
                    $ins = (int)$list['insdate'];
                    if ($ins > 0) {
                        if ($minDate === null || $ins < $minDate) {
                            $minDate = $ins;
                        }
                        if ($maxDate === null || $ins > $maxDate) {
                            $maxDate = $ins;
                        }
                    }

                    $stat = "status_colour info-color-dark";
                    $statTitle = "Outstanding";

                    $repitem = (int)$list['repitem'];
                    $itemnumber = (int)$list['itemnumber'];
                    $itemName = (string)getItemDetails($itemnumber, 'name');
                    $plantNumber = (string)getItemPlant($itemnumber, 'name');
                    $serialNumber = (string)getItemSerial($itemnumber, 'name');
                    $location = trim((string)getItemLocation($itemnumber, 'name') . ' ' . (string)getItemLocation($itemnumber, 'subloc'));
                    $surveyorName = trim((string)($list['surveyor_forename'] ?? '') . ' ' . (string)($list['surveyor_surname'] ?? ''));
                    $surveyorPhone = trim((string)($list['surveyor_phone'] ?? ''));
                    $surveyorMobile = trim((string)($list['surveyor_mobile'] ?? ''));
                    $action = $reviewActions[$repitem] ?? null;
                    $isReadyToSend = $action && (string)($action['status'] ?? '') === 'ready';
                    if ($isReadyToSend) {
                        $readyItemlist[] = $repitem;
                        $readyRepnumbers[] = (string)$list['repnumber'];
                    }
                    $reviewPayload[$repitem] = [
                        'repitem' => $repitem,
                        'repnumber' => (string)$list['repnumber'],
                        'itemnumber' => $itemnumber,
                        'clientnumber' => (int)$list['clientnumber'],
                        'itemName' => $itemName,
                        'plantNumber' => $plantNumber,
                        'serialNumber' => $serialNumber,
                        'location' => $location,
                        'inspectionDate' => $ins > 0 ? date('d-m-Y', $ins) : '',
                        'surveyorId' => (int)($list['esname'] ?? 0),
                        'surveyorName' => $surveyorName,
                        'surveyorEmail' => (string)($list['surveyor_email'] ?? ''),
                        'surveyorPhone' => $surveyorPhone !== '' ? $surveyorPhone : $surveyorMobile,
                        'status' => (string)($action['status'] ?? ''),
                        'adminNote' => (string)($action['admin_note'] ?? ''),
                        'surveyorResponse' => (string)($action['surveyor_response'] ?? ''),
                    ];
                ?>
                    <?php
                    $rowSearchText = strtolower(trim(implode(' ', [
                        $itemnumber,
                        (string)$list['repnumber'],
                        (string)($list['result'] ?? ''),
                        $itemName,
                        $plantNumber,
                        $serialNumber,
                        $location,
                        $ins > 0 ? date('d-m-Y', $ins) : '',
                        (string)($action['status'] ?? ''),
                    ])));
                    ?>
                    <tr id="R<?= $repitem ?>" data-search="<?= reportsOutstandingH($rowSearchText) ?>"
                        data-sort-item="<?= $itemnumber ?>"
                        data-sort-report="<?= reportsOutstandingH($list['repnumber']) ?>"
                        data-sort-description="<?= reportsOutstandingH(strtolower($itemName)) ?>"
                        data-sort-plant="<?= reportsOutstandingH(strtolower($plantNumber)) ?>"
                        data-sort-serial="<?= reportsOutstandingH(strtolower($serialNumber)) ?>"
                        data-sort-location="<?= reportsOutstandingH(strtolower($location)) ?>" data-sort-exam="<?= $ins ?>"
                        data-sort-result="<?= reportsOutstandingH(strtolower((string)($list['result'] ?? ''))) ?>"
                        data-sort-validation="<?= reportsOutstandingH(strtolower((string)($action['status'] ?? 'not reviewed'))) ?>"
                        data-ready="<?= $isReadyToSend ? '1' : '0' ?>">
                        <td class="nowrap col-ready ready-status-cell" data-label="Select">
                            <?php if ($isReadyToSend) { ?>
                                <span class="ready-check" title="Ready to send"><i class="fad fa-check"></i></span>
                            <?php } else { ?>
                                <input class="form-check-input outstanding-row-select" type="checkbox" value="<?= $repitem ?>"
                                    aria-label="Select report <?= reportsOutstandingH($list['repnumber']) ?>"
                                    <?= !$reviewTableReady ? 'disabled' : '' ?>>
                            <?php } ?>
                        </td>
                        <td class="nowrap col-item" data-label="Item"><?= $itemnumber ?></td>
                        <td class="nowrap col-report" data-label="Report"><?= reportsOutstandingH($list['repnumber']) ?>
                        </td>
                        <td class="ellipsis col-desc" data-label="Item Description"><?= reportsOutstandingH($itemName) ?>
                        </td>
                        <td class="nowrap col-plant" data-label="Plant No"><?= reportsOutstandingH($plantNumber) ?></td>
                        <td class="nowrap col-serial" data-label="Serial"><?= reportsOutstandingH($serialNumber) ?></td>
                        <td class="ellipsis col-location" data-label="Location"><?= reportsOutstandingH($location) ?></td>
                        <td class="nowrap col-exam" data-label="Exam Date"><?= $ins > 0 ? date('d-m-Y', $ins) : '' ?></td>
                        <td class="nowrap report-result-cell col-result" data-label="Result">
                            <?= reportsOutstandingResultBadge($list['result'] ?? '') ?></td>
                        <td class="review-status-cell col-validation" id="reviewStatus<?= $repitem ?>"
                            data-label="Validation">
                            <?= reportsOutstandingReviewBadge($action) ?>
                            <?php if ($action && !empty($action['admin_note'])) { ?>
                                <button type="button" class="btn btn-secondary btn-sm ms-1"
                                    onclick="openReviewNoteDetails(<?= $repitem ?>)" title="View note"><i
                                        class="fad fa-note-sticky"></i></button>
                            <?php } ?>
                        </td>

                        <td class="nowrap text-end col-actions" data-label="Actions">
                            <a href="index.php?t=includes/master&amp;p=items.php&amp;view=view&amp;repnumber=<?= urlencode((string)$list['repnumber']) ?>&amp;path=outstanding&amp;data=<?= $clientnumber ?>|19|<?= (int)$list['itemnumber'] ?>"
                                class="btn btn-secondary btn-sm" data-mdb-tooltip-init data-mdb-placement="top"
                                data-mdb-trigger="hover" title="View report">
                                <i class="fad fa-eye"></i>
                            </a>

                            <a href="index.php?t=includes/master&amp;p=formgen.php&amp;mode=reload&amp;formnumber=<?= urlencode((string)$list['reptype']) ?>&amp;repnumber=<?= urlencode((string)$list['repnumber']) ?>&amp;data=<?= (int)$list['clientnumber'] ?>|19|<?= (int)$list['itemnumber'] ?>&amp;path=outstanding&amp;savemode=edit"
                                class="btn btn-secondary btn-sm" data-mdb-tooltip-init data-mdb-placement="top"
                                data-mdb-trigger="hover" title="Edit report">
                                <i class="fad fa-pencil"></i>
                            </a>

                            <button type="button" class="btn btn-success btn-sm" onclick="markReportReady(<?= $repitem ?>)"
                                <?= $reviewTableReady ? '' : 'disabled' ?> data-mdb-tooltip-init data-mdb-placement="top"
                                data-mdb-trigger="hover" title="Mark ready to send">
                                <i class="fad fa-check"></i>
                            </button>

                            <button type="button" class="btn btn-warning btn-sm"
                                onclick="openReviewNoteModal(<?= $repitem ?>)" <?= $reviewTableReady ? '' : 'disabled' ?>
                                data-mdb-tooltip-init data-mdb-placement="top" data-mdb-trigger="hover"
                                title="Send correction note">
                                <i class="fad fa-comment-exclamation"></i>
                            </button>

                            <?php if ($action && $action['status'] !== 'ready') { ?>
                                <button type="button" class="btn btn-danger btn-sm"
                                    onclick="confirmCancelReviewAction(<?= $repitem ?>)" data-mdb-tooltip-init
                                    data-mdb-placement="top" data-mdb-trigger="hover" title="Cancel correction action">
                                    <i class="fad fa-times"></i>
                                </button>
                            <?php } ?>
                        </td>
                    </tr>
                <?php
                    $itemlist[] = $repitem;
                    $counter++;
                }

                $readyRepnumbers = array_values(array_unique($readyRepnumbers));
                $periodFrom = $minDate ? date('d-m-Y', $minDate) : '';
                $periodTo   = $maxDate ? date('d-m-Y', $maxDate) : '';
                ?>
            </tbody>
        </table>
        <div id="outstandingEmptyState" class="text-center text-muted p-3">No reports match your search.</div>
    </div>
</div>

<?php
$_SESSION['returnLanding'] = 'index.php?t=includes/master/&p=reports_outstanding.php&clientnumber=' . $clientnumber;
$_SESSION['items'] = $readyItemlist;
?>

<script>
    (function() {
        const counterEl = document.getElementById('counter');
        if (counterEl) counterEl.textContent = String(<?= (int)$counter ?>);
        const readyCounterEl = document.getElementById('readyCounter');
        if (readyCounterEl) readyCounterEl.textContent = String(<?= (int)count($readyItemlist) ?>);
        const notReadyCounterEl = document.getElementById('notReadyCounter');
        if (notReadyCounterEl) notReadyCounterEl.textContent = String(
            <?= max(0, (int)$counter - (int)count($readyItemlist)) ?>);
        initialiseOutstandingTableSearch();

        const navBox = document.getElementById('navBox');
        if (navBox) {
            navBox.innerHTML =
                '<li class="breadcrumb-item"><a href="index.php?t=includes/master&p=client.php&view=list">Clients</a><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=<?= (int)$clientnumber ?>&view=asset"><?= addslashes(getClientName($clientnumber)) ?></a><i class="fad fa-angle-double-right mx-2 mt-1" aria-hidden="true"></i></li>' +
                '<li class="breadcrumb-item active">Undelivered Reports</li>';
        }
    })();

    function initialiseOutstandingTableSearch() {
        const loading = document.getElementById('loadingObject');
        const table = document.getElementById('datatable');
        const tbody = table ? table.querySelector('tbody') : null;
        const search = document.getElementById('outstandingQuickSearch');
        const visibleCount = document.getElementById('outstandingVisibleCount');
        const totalCount = document.getElementById('outstandingTotalCount');
        const emptyState = document.getElementById('outstandingEmptyState');
        const mobileSort = document.getElementById('outstandingMobileSort');
        if (!table || !tbody || !search) return;

        const rows = Array.from(tbody.querySelectorAll('tr'));
        const sortHeaders = Array.from(table.querySelectorAll('th[data-sort-key]'));
        const sortState = {
            key: '',
            dir: 'asc',
            type: 'text'
        };

        const naturalCompare = new Intl.Collator(undefined, {
            numeric: true,
            sensitivity: 'base'
        });

        const updateCounts = (visible) => {
            if (visibleCount) visibleCount.textContent = String(visible);
            if (totalCount) totalCount.textContent = String(rows.length);
            if (emptyState) emptyState.style.display = visible === 0 ? 'block' : 'none';
        };
        const sortValue = (row, key, type) => {
            const value = row.dataset['sort' + key.charAt(0).toUpperCase() + key.slice(1)] || '';
            if (type === 'number') {
                const num = Number(String(value).replace(/[^0-9.-]/g, ''));
                return Number.isFinite(num) ? num : 0;
            }
            return String(value).toLowerCase();
        };
        const applySort = () => {
            const sorted = rows.slice();
            if (sortState.key) {
                sorted.sort((a, b) => {
                    const av = sortValue(a, sortState.key, sortState.type);
                    const bv = sortValue(b, sortState.key, sortState.type);
                    let result = sortState.type === 'number' ?
                        av - bv :
                        naturalCompare.compare(String(av), String(bv));
                    return sortState.dir === 'desc' ? -result : result;
                });
            }
            sorted.forEach(row => tbody.appendChild(row));
        };
        const setSortHeaderState = () => {
            sortHeaders.forEach(header => {
                header.classList.remove('outstanding-sort-active', 'outstanding-sort-asc',
                    'outstanding-sort-desc');
                if (header.dataset.sortKey === sortState.key) {
                    header.classList.add('outstanding-sort-active', sortState.dir === 'asc' ?
                        'outstanding-sort-asc' : 'outstanding-sort-desc');
                }
            });
        };
        const applySearch = () => {
            const query = search.value.trim().toLowerCase();
            let visible = 0;
            rows.forEach((row, index) => {
                const match = query === '' || (row.dataset.search || row.textContent || '').toLowerCase()
                    .includes(query);
                row.style.display = match ? '' : 'none';
                row.classList.toggle('asset-row-striped', match && (visible % 2 === 1));
                if (match) visible++;
            });
            updateCounts(visible);
        };

        sortHeaders.forEach(header => {
            header.addEventListener('click', () => {
                const key = header.dataset.sortKey || '';
                if (!key) return;
                sortState.dir = sortState.key === key && sortState.dir === 'asc' ? 'desc' : 'asc';
                sortState.key = key;
                sortState.type = header.dataset.sortType || 'text';
                if (mobileSort) mobileSort.value = `${sortState.key}:${sortState.dir}:${sortState.type}`;
                setSortHeaderState();
                applySort();
                applySearch();
            });
        });

        if (mobileSort) {
            mobileSort.addEventListener('change', () => {
                const parts = mobileSort.value.split(':');
                sortState.key = parts[0] || '';
                sortState.dir = parts[1] || 'asc';
                sortState.type = parts[2] || 'text';
                setSortHeaderState();
                applySort();
                applySearch();
            });
        }

        search.addEventListener('input', applySearch);
        rows.forEach((row, index) => row.classList.toggle('asset-row-striped', index % 2 === 1));
        if (loading) loading.style.display = 'none';
        table.style.display = 'table';
        applySearch();
    }

    function getVisibleOutstandingSelectionCheckboxes() {
        return Array.from(document.querySelectorAll('#datatable tbody .outstanding-row-select'))
            .filter(checkbox => {
                const row = checkbox.closest('tr');
                return row && row.style.display !== 'none' && !checkbox.disabled;
            });
    }

    function selectAllVisibleOutstandingReports() {
        const checkboxes = getVisibleOutstandingSelectionCheckboxes();
        if (!checkboxes.length) {
            showResponse('warning', 'No visible reports can be selected.');
            return;
        }
        checkboxes.forEach(checkbox => {
            checkbox.checked = true;
        });
        showResponse('success', `Selected ${checkboxes.length} visible report(s).`);
    }

    function deselectAllVisibleOutstandingReports() {
        const checkboxes = getVisibleOutstandingSelectionCheckboxes();
        if (!checkboxes.length) {
            showResponse('warning', 'No visible reports can be deselected.');
            return;
        }
        checkboxes.forEach(checkbox => {
            checkbox.checked = false;
        });
        showResponse('success', `Deselected ${checkboxes.length} visible report(s).`);
    }

    const OUT_REPNUMBERS = <?= json_encode($readyRepnumbers, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
    const REVIEW_REPORTS = <?= json_encode($reviewPayload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
    const REVIEW_TABLE_READY = <?= $reviewTableReady ? 'true' : 'false' ?>;
    const REVIEW_ENDPOINT = `${ROOT_URL}/includes/reports_outstanding/report_review_actions.php`;
    renderSurveyorResponsesSummary();

    function deliverAll() {
        if (!OUT_REPNUMBERS.length) {
            showResponse('warning', 'No reports are marked ready to send.');
            return;
        }
        window.location.href =
            'index.php?t=includes/master&p=delivery.php&clientnumber=<?= (int)$clientnumber ?>&items=session';
    }

    function reviewActionRequest(action, payload) {
        if (!REVIEW_TABLE_READY) {
            showResponse('warning', 'Review tracking table is not installed yet.');
            return Promise.resolve(null);
        }

        const body = new URLSearchParams(Object.assign({
            action: action,
            tenant: TENANT_URL
        }, payload || {}));

        return fetch(REVIEW_ENDPOINT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: body
        }).then(response => response.json()).then(data => {
            if (!data || data.ok !== true) {
                showResponse('danger', data && data.message ? data.message : 'Unable to update review action.');
                return null;
            }
            return data;
        }).catch(() => {
            showResponse('danger', 'Review action request failed.');
            return null;
        });
    }

    function reloadAfterReview(message) {
        if (message) showResponse('success', message);
        setTimeout(() => window.location.reload(), 500);
    }

    function markReportReady(repitem) {
        reviewActionRequest('ready', {
            repitem: String(repitem)
        }).then(data => {
            if (data) reloadAfterReview('Report marked ready to send.');
        });
    }

    function getSelectedOutstandingRepitems() {
        return Array.from(document.querySelectorAll('.outstanding-row-select:checked'))
            .filter(checkbox => !checkbox.disabled)
            .map(checkbox => Number(checkbox.value))
            .filter(repitem => Number.isFinite(repitem) && repitem > 0);
    }

    function confirmMarkSelectedReady() {
        const repitems = getSelectedOutstandingRepitems();
        if (!repitems.length) {
            showResponse('warning', 'Please select at least one report to mark ready.');
            return;
        }

        const plural = repitems.length === 1 ? 'report' : 'reports';
        const html =
            '<div class="text-center">' +
            '<h5 class="mb-3">Mark selected reports ready?</h5>' +
            `<p class="mb-0">This will mark ${repitems.length} selected ${plural} as Ready to send. They will then be included in delivery and mark-as-sent batch actions.</p>` +
            '</div>';

        loadModalContent(html, 'bulkReadyBox', 'modal-md', 1060, 'true', 'Confirm', 'cancelConfirm', () =>
            markSelectedReportsReady(repitems)
        );
    }

    function markSelectedReportsReady(repitems) {
        reviewActionRequest('ready_bulk', {
            clientnumber: String(<?= (int)$clientnumber ?>),
            repitems: JSON.stringify(repitems)
        }).then(data => {
            if (data) reloadAfterReview(`Marked ${data.updated || repitems.length} report(s) ready to send.`);
        });
    }

    function renderSurveyorResponsesSummary() {
        const wrapper = document.getElementById('surveyorResponsesSummary');
        const countEl = document.getElementById('surveyorResponsesCount');
        const listEl = document.getElementById('surveyorResponsesList');
        if (!wrapper || !countEl || !listEl) return;

        const responses = Object.values(REVIEW_REPORTS || {}).filter(report =>
            String(report.status || '') === 'responded' &&
            String(report.surveyorResponse || '').trim() !== ''
        );
        if (!responses.length) {
            wrapper.style.display = 'none';
            return;
        }

        responses.sort((a, b) => Number(b.repitem || 0) - Number(a.repitem || 0));
        countEl.textContent = String(responses.length);
        listEl.innerHTML = responses.map(report => {
            const repitem = Number(report.repitem || 0);
            const surveyor = report.surveyorName ? ` - ${report.surveyorName}` : '';
            const preview = String(report.surveyorResponse || '').replace(/\s+/g, ' ').trim();
            return `
                <button type="button" class="surveyor-response-jump" onclick="jumpToSurveyorResponse(${repitem})">
                    <span class="response-meta">Report ${escapeReviewHtml(report.repnumber || '')} / Item ${escapeReviewHtml(report.itemnumber || '')}</span>
                    <span class="response-preview">${escapeReviewHtml(preview)}</span>
                    <span class="small text-muted">${escapeReviewHtml(surveyor.replace(/^ - /, ''))}</span>
                </button>`;
        }).join('');
        wrapper.style.display = 'block';
    }

    function jumpToSurveyorResponse(repitem) {
        const row = document.getElementById(`R${Number(repitem)}`);
        if (!row) {
            showResponse('warning', 'Unable to find that report row.');
            return;
        }

        const search = document.getElementById('outstandingQuickSearch');
        if (row.style.display === 'none' && search) {
            search.value = '';
            search.dispatchEvent(new Event('input', {
                bubbles: true
            }));
        }

        row.scrollIntoView({
            behavior: 'smooth',
            block: 'center'
        });
        row.classList.remove('outstanding-row-highlight');
        void row.offsetWidth;
        row.classList.add('outstanding-row-highlight');
        window.setTimeout(() => row.classList.remove('outstanding-row-highlight'), 3200);
    }

    function reportReviewDetailsHtml(report, includeResponse) {
        const phone = report.surveyorPhone ?
            `<a href="tel:${escapeReviewHtml(report.surveyorPhone)}">${escapeReviewHtml(report.surveyorPhone)}</a>` :
            '<span class="text-muted">Not available</span>';
        const email = report.surveyorEmail ?
            `<a href="javascript:void(0)" onclick="openSurveyorReviewMailer(${Number(report.repitem)})">${escapeReviewHtml(report.surveyorEmail)}</a>` :
            '<span class="text-muted">Not available</span>';
        let html = `
        <dl class="review-contact-grid mb-3">
            <dt>Surveyor</dt><dd>${escapeReviewHtml(report.surveyorName || 'Not recorded')}</dd>
            <dt>Email</dt><dd>${email}</dd>
            <dt>Phone</dt><dd>${phone}</dd>
            <dt>Item</dt><dd>${escapeReviewHtml(report.itemName || '')}</dd>
            <dt>Location</dt><dd>${escapeReviewHtml(report.location || '')}</dd>
            <dt>Serial</dt><dd>${escapeReviewHtml(report.serialNumber || '')}</dd>
            <dt>Plant</dt><dd>${escapeReviewHtml(report.plantNumber || '')}</dd>
            <dt>Report</dt><dd>${escapeReviewHtml(report.repnumber || '')}</dd>
            <dt>Inspection</dt><dd>${escapeReviewHtml(report.inspectionDate || '')}</dd>
        </dl>`;
        if (report.adminNote) {
            html +=
                `<div class="alert alert-light border"><strong>Admin note</strong><br>${escapeReviewHtml(report.adminNote).replace(/\n/g, '<br>')}</div>`;
        }
        if (includeResponse && report.surveyorResponse) {
            html +=
                `<div class="alert alert-info border"><strong>Surveyor response</strong><br>${escapeReviewHtml(report.surveyorResponse).replace(/\n/g, '<br>')}</div>`;
        }
        return html;
    }

    function openReviewNoteModal(repitem) {
        const report = REVIEW_REPORTS[repitem];
        if (!report) return;
        const html = reportReviewDetailsHtml(report, true) + `
        <div class="mb-2">
            <label class="form-label" for="reviewNoteText">Actions required</label>
            <textarea id="reviewNoteText" class="form-control" rows="5">${escapeReviewHtml(report.adminNote || '')}</textarea>
        </div>
        <div class="d-flex flex-wrap gap-2">
            <button type="button" class="btn btn-warning" onclick="sendReviewNote(${Number(repitem)})"><i class="fad fa-paper-plane me-1"></i>Send Note</button>
            ${report.surveyorEmail ? `<button type="button" class="btn btn-secondary" onclick="openSurveyorReviewMailer(${Number(repitem)})"><i class="fad fa-envelope me-1"></i>Email Surveyor</button>` : ''}
        </div>`;
        loadModalContent(html, 'reviewNoteBox', 'modal-lg', 1060, 'true', 'Correction Note', 'close');
    }

    function openReviewNoteDetails(repitem) {
        const report = REVIEW_REPORTS[repitem];
        if (!report) return;
        loadModalContent(reportReviewDetailsHtml(report, true), 'reviewNoteDetailsBox', 'modal-lg', 1060, 'true',
            'Review Action', 'close');
    }

    function sendReviewNote(repitem) {
        const note = (document.getElementById('reviewNoteText')?.value || '').trim();
        if (!note) {
            showResponse('warning', 'Please add the action note before sending.');
            return;
        }
        reviewActionRequest('note', {
            repitem: String(repitem),
            note: note
        }).then(data => {
            if (data) reloadAfterReview('Correction note sent to the surveyor action list.');
        });
    }

    function confirmCancelReviewAction(repitem) {
        loadModalContent(
            '<p class="text-center mb-0">Cancel this surveyor action and remove the review note?</p>',
            'cancelReviewBox',
            'modal-sm',
            1060,
            'true',
            'Cancel Action',
            'cancelConfirm',
            () => cancelReviewAction(repitem)
        );
    }

    function cancelReviewAction(repitem) {
        reviewActionRequest('cancel', {
            repitem: String(repitem)
        }).then(data => {
            if (data) reloadAfterReview('Correction action cancelled.');
        });
    }

    function openSurveyorReviewMailer(repitem) {
        const report = REVIEW_REPORTS[repitem];
        if (!report || !report.surveyorEmail) return;
        const note = (document.getElementById('reviewNoteText')?.value || report.adminNote || '').trim();
        const message = [
            `Please review report ${report.repnumber}.`,
            '',
            `Item: ${report.itemName || ''}`,
            `Location: ${report.location || ''}`,
            `Plant: ${report.plantNumber || ''}`,
            `Serial: ${report.serialNumber || ''}`,
            `Inspection date: ${report.inspectionDate || ''}`,
            '',
            note ? `Actions required:\n${note}` : ''
        ].join('\n').trim();
        const payload = {
            clientNumber: String(report.clientnumber || ''),
            clientName: "<?= addslashes(getClientName($clientnumber, 'name')) ?>",
            primaryEmail: report.surveyorEmail,
            secondaryEmail: '',
            subject: `Correction required for report ${report.repnumber}`,
            message: message,
            filePath: '',
            fileName: '',
            addressMode: 'direct',
            mode: 'direct'
        };
        const bytes = new TextEncoder().encode(JSON.stringify(payload));
        let bin = '';
        bytes.forEach(b => bin += String.fromCharCode(b));
        const email64 = btoa(bin);
        const dest =
            `${ROOT_URL}/includes/master/mailer.php?data=${encodeURIComponent(email64)}&mode=popup&tenant=${encodeURIComponent(TENANT_URL)}`;
        loadModalContent(dest, 'popupBox', 'modal-xxl', 1070, 'true', 'Email Surveyor', 'cancelConfirm');
    }

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

    function confirmMarkAllSent() {
        if (!OUT_REPNUMBERS.length) {
            showResponse('warning', 'No reports are marked ready to send.');
            return;
        }

        const html =
            '<div class="text-center">' +
            '<h5 class="mb-3">Mark ready reports as sent?</h5>' +
            '<p class="mb-3">This will update only reports marked Ready to send. Any other reports will stay outstanding.</p>' +
            '<div class="form-check d-inline-flex align-items-center justify-content-center">' +
            '<input class="form-check-input me-2" type="checkbox" id="notifyClient" />' +
            '<label class="form-check-label" for="notifyClient">Notify client by email</label>' +
            '</div>' +
            '</div>';

        loadModalContent(html, "confirmBox", "modal-md", 1060, "true", "Confirm", "cancelConfirm", () => markAllSent());
    }

    async function markAllSent() {
        const notify = !!document.getElementById('notifyClient')?.checked;

        try {
            const res = await fetch(`${ROOT_URL}/includes/master/reports_outstanding.php`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: new URLSearchParams({
                    FUNCTION: 'markAllSent',
                    clientnumber: String(<?= (int)$clientnumber ?>),
                    repnumbers: JSON.stringify(OUT_REPNUMBERS),
                    tenant: TENANT_URL
                })
            });

            const data = await res.json();

            if (data.status === 'success') {
                showResponse('success', `Marked ${data.updated} item(s) as sent.`);
            } else if (data.status === 'warning') {
                showResponse('warning', data.message || 'No outstanding reports found.');
            } else {
                showResponse('danger', data.message || 'Unable to mark reports as sent.');
            }

            if (notify && data.status === 'success') {
                killModal('confirmBox');

                removeReadyRowsFromOutstandingTable(data.updated || OUT_REPNUMBERS.length);



                const from = "<?= $periodFrom ?>";
                const to = "<?= $periodTo ?>";
                const periodText = (from && to) ? `for the period ${from} to ${to}` : '';

                const subject = "Your reports are ready";
                const portalLink = "https://<?= getcompanydetails('web') ?>/client";

                const message =
                    `Your reports ${periodText} are ready for viewing via your client portal.\n\n\n\n${portalLink}`
                    .replace(/\s+/g, ' ')
                    .replace(/\n /g, '\n')
                    .trim();

                const payload = {
                    clientNumber: String(<?= (int)$clientnumber ?>),
                    clientName: "<?= addslashes(getClientName($clientnumber, 'name')) ?>",
                    primaryEmail: "",
                    secondaryEmail: "",
                    subject: subject,
                    message: message,
                    filePath: "",
                    fileName: "",
                    addressMode: "delivery",
                    mode: "delivery"
                };

                const toBase64Utf8 = (str) => {
                    const bytes = new TextEncoder().encode(str);
                    let bin = '';
                    bytes.forEach(b => bin += String.fromCharCode(b));
                    return btoa(bin);
                };

                const email64 = toBase64Utf8(JSON.stringify(payload));

                const dest = encodeURI(
                    `${ROOT_URL}/includes/master/mailer.php?data=${encodeURIComponent(email64)}&mode=popup&tenant=${TENANT_URL}`
                );

                loadModalContent(dest, "popupBox", "modal-xxl", 1060, "true", "Notify Client", "cancelConfirm");
                return;
            }

            killModal('confirmBox');
            if (data.status === 'success') {
                removeReadyRowsFromOutstandingTable(data.updated || OUT_REPNUMBERS.length);
            }


        } catch (e) {
            showResponse('danger', 'Request failed while marking reports as sent.');
        }
    }

    function removeReadyRowsFromOutstandingTable(updatedCount) {
        const table = document.getElementById('datatable');
        const tbody = table ? table.querySelector('tbody') : null;
        if (!tbody) return;

        const readySet = new Set(OUT_REPNUMBERS.map(String));
        tbody.querySelectorAll('tr').forEach(row => {
            if (readySet.has(String(row.dataset.sortReport || ''))) {
                row.remove();
            }
        });

        const remaining = tbody.querySelectorAll('tr').length;
        const counterEl = document.getElementById('counter');
        if (counterEl) counterEl.textContent = String(remaining);
        const readyCounterEl = document.getElementById('readyCounter');
        if (readyCounterEl) readyCounterEl.textContent = '0';
        const notReadyCounterEl = document.getElementById('notReadyCounter');
        if (notReadyCounterEl) notReadyCounterEl.textContent = String(remaining);
        const visibleCount = document.getElementById('outstandingVisibleCount');
        if (visibleCount) visibleCount.textContent = String(remaining);
        const totalCount = document.getElementById('outstandingTotalCount');
        if (totalCount) totalCount.textContent = String(remaining);
    }
</script>
