<?php ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/security.php';

$tenantSegment = enrep_tenant_segment();
if ($tenantSegment !== '' && file_exists('../../' . $tenantSegment . '/config.php')) {
    require_once('../../' . $tenantSegment . '/config.php');
}
if (file_exists('/config.php')) require_once('/config.php');

if (!isset($GLOBALS['con']) || !($GLOBALS['con'] instanceof mysqli)) {
    enrep_fail(400, 'Tenant config not found');
}
require_once __DIR__ . '/../includes/master/form_functions.php';
enrep_require_user();

$clientNumber = enrep_request_int('clientnumber');
$chain = enrep_request_string('chain', '', 80);
$dateStr = enrep_request_string('date', '', 40);
$surveyor = enrep_request_int('surveyor');
$initialExamType = enrep_request_string('initial_examType', '', 10);
$pnaMode = enrep_request_enum('pna_mode', ['pna', 'clone_non_pna', ''], '');
$pnaInitialMode = enrep_request_enum('pna_initial_mode', ['pna', 'initial', ''], 'pna');
$pnaReason = enrep_request_string('pna_reason', 'Item not presented for examination.', 1000);
$noteText = enrep_request_string('note_text', '', 5000);
$noteApply = enrep_request_int('note_apply') === 1;
$noteType = enrep_request_string('note_type', '', 40);
$imageMode = (enrep_request_int('imageMode') === 1 || enrep_request_int('imageset') === 1) ? 1 : 0;
$tagMode = (enrep_request_int('tagMode') === 1 || enrep_request_int('tagmode') === 1) ? 1 : 0;
$groupsJson = enrep_request_string('groups', '', 1000000);

if ($clientNumber <= 0) enrep_fail(400, 'Invalid clientnumber');
if ($surveyor <= 0) enrep_fail(400, 'Invalid surveyor');
if ($dateStr === '') enrep_fail(400, 'Missing date');
if ($groupsJson === '') enrep_fail(400, 'Missing groups');

$groups = json_decode($groupsJson, true);
if (!is_array($groups)) enrep_fail(400, 'Invalid groups JSON');

$rapidCleanItems = static function ($values): array {
    return array_values(array_filter(enrep_int_list_from_mixed(is_array($values) ? $values : []), static function ($value) {
        return $value > 0;
    }));
};

$initialItems = $rapidCleanItems($groups['initialItems'] ?? []);
$standardCloneItems = $rapidCleanItems($groups['standardCloneItems'] ?? []);
$pnaWithPriorCloneItems = $rapidCleanItems($groups['pnaWithPriorCloneItems'] ?? []);
$pnaInitialItems = $rapidCleanItems($groups['pnaInitialItems'] ?? []);

if ($pnaMode === '' && (count($pnaWithPriorCloneItems) > 0 || count($pnaInitialItems) > 0)) {
    $pnaMode = 'pna';
}

$totalItems = count($initialItems) + count($standardCloneItems) + count($pnaWithPriorCloneItems) + count($pnaInitialItems);
if ($totalItems <= 0) enrep_fail(400, 'No items to process');
if ($totalItems > 1000) enrep_fail(400, 'Too many items to process');

$dt = strtotime($dateStr);
if ($dt <= 0) enrep_fail(400, 'Invalid date');

$allowedExamTypes = ["500","502","503","504","506","900","511","512","513","514","515","516","517","518"];
$rapidAllowFile = ($tenantSegment !== '') ? ('../../' . $tenantSegment . '/output/rapidAllow.php') : '';
if ($rapidAllowFile !== '' && 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, static fn($reptype) => preg_match('/^\d+$/', $reptype));
        $allowedExamTypes = array_values(array_unique(array_merge($allowedExamTypes, $rapidAllow)));
    }
}

if ((count($initialItems) > 0 || (count($pnaInitialItems) > 0 && $pnaInitialMode === 'initial')) && ($initialExamType === '' || !in_array($initialExamType, $allowedExamTypes, true))) {
    enrep_fail(400, 'Invalid initial examType');
}

$applyNote = false;
$noteTypeNorm = '';
$noteTextTrim = trim((string)$noteText);

if ($noteApply && $noteTextTrim !== '' && strtolower($noteTextTrim) !== 'none') {
    if ($noteType === 'observation' || $noteType === 'recommendation') {
        $applyNote = true;
        $noteTypeNorm = $noteType;
    } else {
        enrep_fail(400, 'Invalid note_type');
    }
} else {
    $noteTextTrim = '';
}

$GLOBALS['RR_REP_BASE'] = time();
$GLOBALS['RR_REP_NEXT'] = (int)$GLOBALS['RR_REP_BASE'];

function rr_repExists(int $rep): bool {
    $stmt = $GLOBALS['con']->prepare("SELECT 1 FROM `reportitems` WHERE `repnumber`=? LIMIT 1") or enrep_fail(500, 'Unable to check report number');
    $stmt->bind_param('i', $rep);
    $stmt->execute();
    $r = $stmt->get_result();
    $stmt->close();
    return ($r && $r->num_rows > 0);
}

function rr_nextRepNumber(): int {
    $n = (int)($GLOBALS['RR_REP_NEXT'] ?? time());
    if ($n < 1) $n = time();
    $guard = 0;
    while (rr_repExists($n)) {
        $n++;
        $guard++;
        if ($guard > 5000) enrep_fail(500, 'Unable to generate unique repnumber');
    }
    $GLOBALS['RR_REP_NEXT'] = $n + 1;
    return $n;
}

function rr_fetchLatestReportRow(int $client, int $item, bool $nonPnaOnly): ?array {
    $sql = "SELECT * FROM `reportitems` WHERE `clientnumber`=? AND `itemnumber`=? ";
    if ($nonPnaOnly) $sql .= " AND `reptype` != '503' AND UPPER(COALESCE(`result`,'')) != 'PNA' ";
    $sql .= " ORDER BY ABS(`repitem`) DESC LIMIT 1";
    $stmt = $GLOBALS['con']->prepare($sql) or enrep_fail(500, 'Unable to load source report');
    $stmt->bind_param('ii', $client, $item);
    $stmt->execute();
    $r = $stmt->get_result();
    $stmt->close();
    if (!$r || $r->num_rows === 0) return null;
    $row = $r->fetch_assoc();
    return array_merge($row, enrepReportDataFromRow($row));
}

function rr_fetchPlantFrequencyMonths(string $code): int {
    $stmt = $GLOBALS['con']->prepare("SELECT `frequency` FROM `dd_plant` WHERE `code`=? LIMIT 1");
    if (!$stmt) return 6;
    $stmt->bind_param('s', $code);
    $stmt->execute();
    $q = $stmt->get_result();
    $stmt->close();
    if (!$q) return 6;
    $r = mysqli_fetch_assoc($q);
    $m = intval($r['frequency'] ?? 6);
    return ($m > 0 ? $m : 6);
}

function rr_fetchItemMeta(int $item): ?array {
    $stmt = $GLOBALS['con']->prepare("SELECT `clientnumber`,`code`,`linked`,`currdate` FROM `itemdetails` WHERE `itemnumber`=? LIMIT 1") or enrep_fail(500, 'Unable to load item details');
    $stmt->bind_param('i', $item);
    $stmt->execute();
    $r = $stmt->get_result();
    $stmt->close();
    if (!$r || $r->num_rows === 0) return null;
    return $r->fetch_assoc();
}

function rr_reportValue(array $row, string $key, $default = null) {
    return array_key_exists($key, $row) ? $row[$key] : $default;
}

function rr_insertReportItem(array $values): void {
    $columns = array_values(array_filter(enrepReportFixedFields(), static function ($column): bool {
        return $column !== 'repitem';
    }));
    $reportData = [];
    foreach (enrepReportDataFields() as $field) {
        if (array_key_exists($field, $values)) {
            $reportData[$field] = $values[$field];
        }
    }
    $columns[] = 'reportdata';
    $values['reportdata'] = enrepReportDataJson($reportData);

    $params = [];
    foreach ($columns as $column) {
        $params[] = array_key_exists($column, $values) ? $values[$column] : null;
    }

    foreach ($params as $idx => $param) {
        if (is_bool($param)) {
            $params[$idx] = $param ? '1' : '0';
        }
    }

    $quotedColumns = '`' . implode('`,`', $columns) . '`';
    $placeholders = implode(',', array_fill(0, count($columns), '?'));
    $stmt = $GLOBALS['con']->prepare("INSERT INTO `reportitems` (" . $quotedColumns . ") VALUES (" . $placeholders . ")")
        or enrep_fail(500, 'Unable to create report');

    $types = str_repeat('s', count($params));
    $refs = [&$types];
    foreach ($params as $idx => &$param) {
        $refs[] = &$param;
    }
    unset($param);

    if (!call_user_func_array([$stmt, 'bind_param'], $refs)) {
        $stmt->close();
        enrep_fail(500, 'Unable to bind report values');
    }

    $stmt->execute();
    if ($stmt->error) {
        $error = $stmt->error;
        $stmt->close();
        enrep_fail(500, 'Unable to create report: ' . $error);
    }
    $stmt->close();
}

function rr_insertClone(
    int $clientNumber,
    int $itemNumber,
    array $cx,
    int $dt,
    int $surveyor,
    bool $applyNote,
    string $noteTypeNorm,
    string $noteText,
    bool $forcePna,
    string $pnaReason
): int {
    $itemMeta = rr_fetchItemMeta($itemNumber);
    if (!$itemMeta) enrep_fail(400, "Item meta not found for item " . $itemNumber);

    $freqMonths = rr_fetchPlantFrequencyMonths((string)$itemMeta['code']);
    $nx = strtotime(date('d-m-Y', strtotime('+' . $freqMonths . ' months', $dt)));
    $nw = time();

    $result = (string)($cx['result'] ?? 'PASS');
    $obs = (string)($cx['obs'] ?? 'None');

    if ($forcePna) {
        $result = 'PNA';
        $cx['examType'] = 503;
        $cx['pnareason'] = $pnaReason;
        $obs = 'None';
    } else {
        if ($applyNote) {
            $obs = $noteText;
            if ($noteTypeNorm === 'observation') $result = 'OBS';
        }
    }

    $cx['result'] = $result;
    $cx['resultOfExam'] = $result;

    $repnumber = rr_nextRepNumber();

    rr_insertReportItem([
        'repnumber' => (string)$repnumber,
        'master_report_id' => null,
        'repnumberold' => rr_reportValue($cx, 'repnumber', '0'),
        'olddate' => rr_reportValue($cx, 'insdate'),
        'insdate' => $dt,
        'nextDate' => $nx,
        'repdate' => $nw,
        'delivery' => 0,
        'clientnumber' => $clientNumber,
        'itemnumber' => $itemNumber,
        'esname' => $surveyor,
        'adefect' => rr_reportValue($cx, 'adefect', 'None'),
        'bdefect' => rr_reportValue($cx, 'bdefect', 'None'),
        'obs' => $obs,
        'pnareason' => rr_reportValue($cx, 'pnareason'),
        'partialReason' => rr_reportValue($cx, 'partialReason'),
        'ffcomments' => rr_reportValue($cx, 'ffcomments'),
        'code' => rr_reportValue($cx, 'code'),
        'viewed' => rr_reportValue($cx, 'viewed', '0'),
        'history' => rr_reportValue($cx, 'history', '0'),
        'changeScheme' => rr_reportValue($cx, 'changeScheme', '0'),
        'resultOfExam' => rr_reportValue($cx, 'resultOfExam', $result),
        'lastReportSeen' => rr_reportValue($cx, 'lastReportSeen'),
        'examType' => rr_reportValue($cx, 'examType', rr_reportValue($cx, 'reptype')),
        'partsCovered' => rr_reportValue($cx, 'partsCovered', '0'),
        'lease_or_hire' => rr_reportValue($cx, 'lease_or_hire'),
        'partsInaccessible' => rr_reportValue($cx, 'partsInaccessible', '0'),
        'conditionInternal' => rr_reportValue($cx, 'conditionInternal', '0'),
        'conditionExternal' => rr_reportValue($cx, 'conditionExternal', '0'),
        'conditionFittings' => rr_reportValue($cx, 'conditionFittings', '0'),
        'protectiveDevices' => rr_reportValue($cx, 'protectiveDevices'),
        '9b1' => rr_reportValue($cx, '9b1', '0'),
        '9b2' => rr_reportValue($cx, '9b2', '0'),
        '9b3' => rr_reportValue($cx, '9b3', '0'),
        'processConditions' => rr_reportValue($cx, 'processConditions'),
        'class' => rr_reportValue($cx, 'class', '0'),
        'ebond' => rr_reportValue($cx, 'ebond', '0.1'),
        'ires' => rr_reportValue($cx, 'ires', '999'),
        'volts' => rr_reportValue($cx, 'volts', '230'),
        'nature' => rr_reportValue($cx, 'nature'),
        'test_procedure' => rr_reportValue($cx, 'test_procedure'),
        'process_conditions' => rr_reportValue($cx, 'process_conditions'),
        'effective' => rr_reportValue($cx, 'effective'),
        'particulars' => rr_reportValue($cx, 'particulars'),
        'other_comments' => rr_reportValue($cx, 'other_comments'),
        'usage_comments' => rr_reportValue($cx, 'usage_comments'),
        'noise' => rr_reportValue($cx, 'noise'),
        'intended_performance' => rr_reportValue($cx, 'intended_performance'),
        'achieving_perfomance' => rr_reportValue($cx, 'achieving_perfomance'),
        'repair_details' => rr_reportValue($cx, 'repair_details'),
        'rack' => rr_reportValue($cx, 'rack'),
        'rackRun' => rr_reportValue($cx, 'rackRun'),
        'beam' => rr_reportValue($cx, 'beam'),
        'accessories' => rr_reportValue($cx, 'accessories'),
        'handling' => rr_reportValue($cx, 'handling'),
        'stability' => rr_reportValue($cx, 'stability'),
        'clutch' => rr_reportValue($cx, 'clutch'),
        'safety' => rr_reportValue($cx, 'safety'),
        'frequency' => rr_reportValue($cx, 'frequency'),
        'reptype' => rr_reportValue($cx, 'reptype', rr_reportValue($cx, 'examType')),
        'result' => $result,
    ]);

    $stmt2 = $GLOBALS['con']->prepare("UPDATE `itemdetails` SET `currdate`=?, `duedate`=?, `history`=?, `lastReport`=? WHERE `itemnumber`=?")
        or enrep_fail(500, 'Unable to update item details');
    $hist = (string)($cx['history'] ?? '');
    $stmt2->bind_param('iissi', $dt, $nx, $hist, $result, $itemNumber);
    $stmt2->execute();
    $stmt2->close();

    return $repnumber;
}

function rr_insertInitial(
    int $clientNumber,
    int $itemNumber,
    int $dt,
    int $surveyor,
    string $examType,
    bool $applyNote,
    string $noteTypeNorm,
    string $noteText,
    string $pnaReason
): int {
    $itemMeta = rr_fetchItemMeta($itemNumber);
    if (!$itemMeta) enrep_fail(400, "Item meta not found for item " . $itemNumber);

    $freqMonths = rr_fetchPlantFrequencyMonths((string)$itemMeta['code']);
    $nx = strtotime(date('d-m-Y', strtotime('+' . $freqMonths . ' months', $dt)));
    $nw = time();

    $repnumber = rr_nextRepNumber();

    $result = 'PASS';
    $obs = 'None';
    $pnareason = null;

    if ($examType === '503' || $examType === 503) {
        $result = 'PNA';
        $pnareason = $pnaReason;
        $obs = 'None';
    } else {
        if ($applyNote) {
            $obs = $noteText;
            if ($noteTypeNorm === 'observation') $result = 'OBS';
        }
    }

    $startDate = intval($itemMeta['currdate'] ?? 0);
    rr_insertReportItem([
        'repnumber' => (string)$repnumber,
        'master_report_id' => null,
        'repnumberold' => null,
        'olddate' => $startDate,
        'insdate' => $dt,
        'nextDate' => $nx,
        'repdate' => $nw,
        'delivery' => 0,
        'clientnumber' => $clientNumber,
        'itemnumber' => $itemNumber,
        'esname' => $surveyor,
        'adefect' => 'None',
        'bdefect' => 'None',
        'obs' => $obs,
        'pnareason' => $pnareason,
        'resultOfExam' => $result,
        'examType' => $examType,
        'reptype' => $examType,
        'result' => $result,
    ]);

    $stmt2 = $GLOBALS['con']->prepare("UPDATE `itemdetails` SET `currdate`=?, `duedate`=?, `lastReport`=? WHERE `itemnumber`=?")
        or enrep_fail(500, 'Unable to update item details');
    $stmt2->bind_param('iisi', $dt, $nx, $result, $itemNumber);
    $stmt2->execute();
    $stmt2->close();

    return $repnumber;
}

$created = [];

foreach ($standardCloneItems as $item) {
    if ($item <= 0) continue;
    $cx = rr_fetchLatestReportRow($clientNumber, $item, false);
    if (!$cx) continue;
    $newRep = rr_insertClone($clientNumber, $item, $cx, $dt, $surveyor, $applyNote, $noteTypeNorm, $noteTextTrim, false, $pnaReason);
    $created[] = ['item' => $item, 'rep' => $newRep];
}

foreach ($pnaWithPriorCloneItems as $item) {
    if ($item <= 0) continue;
    $forcePna = ($pnaMode === 'pna');
    $cx = rr_fetchLatestReportRow($clientNumber, $item, ($pnaMode === 'clone_non_pna'));
    if (!$cx) continue;
    $newRep = rr_insertClone($clientNumber, $item, $cx, $dt, $surveyor, $applyNote, $noteTypeNorm, $noteTextTrim, $forcePna, $pnaReason);
    $created[] = ['item' => $item, 'rep' => $newRep];
}

foreach ($pnaInitialItems as $item) {
    if ($item <= 0) continue;
    if ($pnaInitialMode === 'initial') {
        $newRep = rr_insertInitial($clientNumber, $item, $dt, $surveyor, $initialExamType, $applyNote, $noteTypeNorm, $noteTextTrim, $pnaReason);
    } else {
        $newRep = rr_insertInitial($clientNumber, $item, $dt, $surveyor, '503', false, '', '', $pnaReason);
    }
    $created[] = ['item' => $item, 'rep' => $newRep];
}

foreach ($initialItems as $item) {
    if ($item <= 0) continue;
    $newRep = rr_insertInitial($clientNumber, $item, $dt, $surveyor, $initialExamType, $applyNote, $noteTypeNorm, $noteTextTrim, $pnaReason);
    $created[] = ['item' => $item, 'rep' => $newRep];
}

$now = time();
$repsJson = json_encode($created);
if (!is_string($repsJson)) {
    enrep_fail(500, 'Unable to record RapidRep history');
}

if ($chain === '') $chain = '0';

$stmt = $GLOBALS['con']->prepare("DELETE FROM `rapid_history` WHERE `clientnumber`=? AND `chain`=?")
    or enrep_fail(500, 'Unable to update RapidRep history');
$stmt->bind_param('is', $clientNumber, $chain);
$stmt->execute();
$stmt->close();

$stmt = $GLOBALS['con']->prepare("INSERT INTO `rapid_history` VALUES(NULL,?,?,?,?)")
    or enrep_fail(500, 'Unable to update RapidRep history');
$stmt->bind_param('issi', $clientNumber, $chain, $repsJson, $now);
$stmt->execute();
$stmt->close();


if (isset($admin_con) && ($admin_con instanceof mysqli) && !empty($created)) {

    $now = time();
    $tenant = defined('TENANT_URL') ? (string)TENANT_URL : '/' . $tenantSegment;
    $jobType = 'report_pdf';
    $queuePdf = ($imageMode !== 1 && $tagMode !== 1);

    $stmtQ = $queuePdf ? $admin_con->prepare("
        INSERT INTO `pdf_queue`
            (`tenant`,`clientnumber`,`itemnumber`,`repnumber`,`job_type`,`status`,`attempts`,`locked_until`,`created_at`)
        VALUES
            (?,?,?,?,?,'pending',0,0,?)
        ON DUPLICATE KEY UPDATE
            `status`='pending',
            `attempts`=0,
            `locked_until`=0,
            `job_type`=VALUES(`job_type`),
            `last_error`=NULL,
            `created_at`=VALUES(`created_at`)
    ") : null;

    if ($stmtQ) {
        foreach ($created as $row) {
            $item = intval($row['item'] ?? 0);
            $rep  = intval($row['rep'] ?? 0);
            if ($item <= 0 || $rep <= 0) continue;

            $stmtQ->bind_param('siiisi', $tenant, $clientNumber, $item, $rep, $jobType, $now);
            $stmtQ->execute();
        }
        $stmtQ->close();
    }
}

$response = "success|" . count($created);
if (($imageMode === 1 || $tagMode === 1) && !empty($created)) {
    $response .= '|' . rawurlencode(json_encode([
        'imageMode' => $imageMode,
        'tagMode' => $tagMode,
        'reports' => $created,
    ]));
}

echo $response;
