<?php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../../functions/security.php';

$loadedConfig = '';
$tenant = enrep_tenant_segment($_POST['tenant'] ?? $_GET['tenant'] ?? null);

if ($tenant !== '' && file_exists('../../../' . $tenant . '/config.php')) {
    require_once('../../../' . $tenant . '/config.php');
    $loadedConfig = '../../../' . $tenant . '/config.php';
} elseif (file_exists('/config.php')) {
    require_once('/config.php');
    $loadedConfig = '/config.php';
}

$con = $GLOBALS['con'] ?? null;
if (!$con) {
    echo json_encode([
        'success' => false,
        'message' => 'Database connection not available',
        'total' => 0,
        'filtered' => 0,
        'rows' => [],
        'recordsTotal' => 0,
        'recordsFiltered' => 0,
        'data' => []
    ]);
    exit;
}

enrep_require_user();
$con->set_charset('utf8mb4');

function assetGridBindParams(mysqli_stmt $stmt, string $types, array $params): void
{
    if ($types !== '' && !empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
}

function assetGridColumnExists(mysqli $con, string $table, string $column): bool
{
    $table = preg_replace('/[^A-Za-z0-9_]/', '', $table);
    $column = preg_replace('/[^A-Za-z0-9_]/', '', $column);
    if ($table === '' || $column === '') {
        return false;
    }

    $stmt = $con->prepare("SELECT `{$column}` FROM `{$table}` LIMIT 1");
    if (!$stmt) {
        return false;
    }

    $stmt->execute();
    $stmt->close();

    return true;
}

function assetGridPnaStreakFromRecentResults(string $recentResults): int
{
    $results = array_slice(array_map(static function ($value) {
        return strtoupper(trim((string)$value));
    }, explode(',', $recentResults)), 0, 4);

    if (($results[0] ?? '') !== 'PNA') {
        return 0;
    }

    $streak = 1;
    for ($i = 1; $i < count($results); $i++) {
        if ($results[$i] !== 'PNA') {
            break;
        }
        $streak++;
    }

    return $streak >= 2 ? $streak : 0;
}

function assetGridFetchPnaStreaks(mysqli $con, int $client, array $itemnumbers): array
{
    $itemnumbers = array_values(array_unique(array_filter(array_map('intval', $itemnumbers), static function ($value) {
        return $value > 0;
    })));

    if (empty($itemnumbers)) {
        return [];
    }

    $placeholders = implode(',', array_fill(0, count($itemnumbers), '?'));
    $types = 'i' . str_repeat('i', count($itemnumbers));
    $params = array_merge([$client], $itemnumbers);

    $sql = "
        SELECT itemnumber, UPPER(TRIM(COALESCE(result, ''))) AS result
        FROM reportitems
        WHERE clientnumber = ?
          AND itemnumber IN ({$placeholders})
        ORDER BY itemnumber ASC, ABS(repitem) DESC
    ";

    $stmt = $con->prepare($sql);
    if (!$stmt) {
        return [];
    }

    assetGridBindParams($stmt, $types, $params);
    $stmt->execute();
    $res = $stmt->get_result();

    $recentResults = [];
    while ($row = $res->fetch_assoc()) {
        $itemnumber = (int)($row['itemnumber'] ?? 0);
        if ($itemnumber > 0 && count($recentResults[$itemnumber] ?? []) < 4) {
            $recentResults[$itemnumber][] = (string)($row['result'] ?? '');
        }
    }
    $stmt->close();

    $streaks = [];
    foreach ($recentResults as $itemnumber => $results) {
        $streaks[$itemnumber] = assetGridPnaStreakFromRecentResults(implode(',', $results));
    }

    return $streaks;
}

function assetGridFetchSchemeBadges(mysqli $con, array $itemnumbers): array
{
    $itemnumbers = array_values(array_unique(array_filter(array_map('intval', $itemnumbers), static function ($value) {
        return $value > 0;
    })));

    if (empty($itemnumbers)) {
        return [];
    }

    $placeholders = implode(',', array_fill(0, count($itemnumbers), '?'));
    $types = str_repeat('i', count($itemnumbers));
    $badges = [];

    foreach ($itemnumbers as $itemnumber) {
        $badges[$itemnumber] = [
            'ws_id' => 0,
            'ws_no' => '',
            'ws_renewal' => 0,
            'lws_id' => 0,
            'lws_no' => '',
        ];
    }

    $wsSql = "
        SELECT wi.itemnumber, ws.id AS ws_id, ws.no AS ws_no, ws.renewal AS ws_renewal
        FROM wsitems wi
        INNER JOIN (
            SELECT itemnumber, MAX(id) AS max_id
            FROM wsitems
            WHERE itemnumber IN ({$placeholders})
            GROUP BY itemnumber
        ) latest_wi ON latest_wi.max_id = wi.id
        INNER JOIN writtenscheme ws ON ws.id = wi.wsnumber
    ";
    $stmt = $con->prepare($wsSql);
    if ($stmt) {
        assetGridBindParams($stmt, $types, $itemnumbers);
        $stmt->execute();
        $res = $stmt->get_result();
        while ($res && ($row = $res->fetch_assoc())) {
            $itemnumber = (int)($row['itemnumber'] ?? 0);
            if (isset($badges[$itemnumber])) {
                $badges[$itemnumber]['ws_id'] = (int)($row['ws_id'] ?? 0);
                $badges[$itemnumber]['ws_no'] = (string)($row['ws_no'] ?? '');
                $badges[$itemnumber]['ws_renewal'] = (int)($row['ws_renewal'] ?? 0);
            }
        }
        $stmt->close();
    }

    $lwsSql = "
        SELECT li.itemnumber, lws.id AS lws_id, lws.no AS lws_no
        FROM lwsitems li
        INNER JOIN (
            SELECT itemnumber, MAX(id) AS max_id
            FROM lwsitems
            WHERE itemnumber IN ({$placeholders})
            GROUP BY itemnumber
        ) latest_li ON latest_li.max_id = li.id
        INNER JOIN lwrittenscheme lws ON lws.id = li.lwsnumber
    ";
    $stmt = $con->prepare($lwsSql);
    if ($stmt) {
        assetGridBindParams($stmt, $types, $itemnumbers);
        $stmt->execute();
        $res = $stmt->get_result();
        while ($res && ($row = $res->fetch_assoc())) {
            $itemnumber = (int)($row['itemnumber'] ?? 0);
            if (isset($badges[$itemnumber])) {
                $badges[$itemnumber]['lws_id'] = (int)($row['lws_id'] ?? 0);
                $badges[$itemnumber]['lws_no'] = (string)($row['lws_no'] ?? '');
            }
        }
        $stmt->close();
    }

    return $badges;
}

function assetGridFetchPuwerBadges(mysqli $con, int $client, array $itemnumbers): array
{
    $itemnumbers = array_values(array_unique(array_filter(array_map('intval', $itemnumbers), static function ($value) {
        return $value > 0;
    })));

    if ($client <= 0 || empty($itemnumbers)) {
        return [];
    }

    $wanted = array_fill_keys($itemnumbers, true);
    $badges = [];

    $stmt = $con->prepare("
        SELECT id, set_title, itemnumbers_json
        FROM puwer_item_sets
        WHERE clientnumber = ?
          AND status = 1
        ORDER BY id DESC
    ");
    if (!$stmt) {
        return [];
    }

    $stmt->bind_param('i', $client);
    $stmt->execute();
    $res = $stmt->get_result();

    while ($res && ($row = $res->fetch_assoc())) {
        $setId = (int)($row['id'] ?? 0);
        if ($setId <= 0) {
            continue;
        }

        $rawItems = (string)($row['itemnumbers_json'] ?? '');
        $setItems = json_decode($rawItems, true);
        if (!is_array($setItems)) {
            preg_match_all('/\d+/', $rawItems, $matches);
            $setItems = $matches[0] ?? [];
        }

        foreach ($setItems as $setItem) {
            $itemnumber = (int)$setItem;
            if (!isset($wanted[$itemnumber]) || isset($badges[$itemnumber])) {
                continue;
            }

            $badges[$itemnumber] = [
                'puwer_set_id' => $setId,
                'puwer_set_title' => (string)($row['set_title'] ?? ''),
            ];
        }

        if (count($badges) >= count($wanted)) {
            break;
        }
    }
    $stmt->close();

    return $badges;
}

function assetGridSearchTerms(string $searchRaw): array
{
    $searchRaw = trim($searchRaw);
    if ($searchRaw === '' || strlen($searchRaw) < 2) {
        return [];
    }

    return array_values(array_filter(array_map(static function ($term) {
        $term = preg_replace('/\s+/', ' ', trim((string)$term));
        return strlen($term) >= 2 ? $term : '';
    }, explode(',', $searchRaw)), static function ($term) {
        return $term !== '';
    }));
}

function assetGridLikeTerm(string $term): string
{
    return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $term);
}

function assetGridStatusFilter(string $statusRaw): string
{
    $allowed = ['overdue', 'pending', 'not_due'];
    $status = strtolower(trim($statusRaw));
    return in_array($status, $allowed, true) ? $status : '';
}

function assetGridAssignedSurveyorScopeClause(): array
{
    $sessionUserId = (int)($_SESSION['userid'] ?? 0);
    $sessionAccess = (int)($_SESSION['access'] ?? 0);
    if (($_SESSION['usertype'] ?? '') !== 'surveyor' || $sessionAccess !== 3 || $sessionUserId <= 0) {
        return ['', '', []];
    }

    return ["
        AND EXISTS (
            SELECT 1
            FROM surveyor_assignments sa
            WHERE sa.surveyor = ?
              AND sa.client_id = a.clientnumber
              AND sa.status = 1
              AND (
                  (COALESCE(sa.asset_id, 0) > 0 AND sa.asset_id = a.itemnumber)
                  OR (COALESCE(sa.asset_id, 0) = 0 AND COALESCE(sa.site_id, 0) > 0 AND sa.site_id = a.locnumber)
                  OR (COALESCE(sa.asset_id, 0) = 0 AND COALESCE(sa.site_id, 0) = 0)
              )
        )
    ", 'i', [$sessionUserId]];
}

$page = max(1, enrep_request_int('page', 1));
$perPage = max(1, min(1000, enrep_request_int('per_page', 25)));
$mode = enrep_request_enum('mode', ['page', 'all'], 'page');
$searchRaw = enrep_request_string('search', '', 200);
$sortField = enrep_request_string('sort_field', 'duedate', 80);
$sortDir = strtolower((string)($_POST['sort_dir'] ?? 'asc')) === 'desc' ? 'DESC' : 'ASC';
$statusFilter = strtolower((string)($_POST['status_filter'] ?? ''));
$statusFilter = assetGridStatusFilter($statusFilter);
$client = enrep_request_int('clientnumber');
$status = enrep_request_int('status', 1);
$hasPlantRowColour = assetGridColumnExists($con, 'dd_plant', 'row_colour');
$ddPlantJoin = $hasPlantRowColour
    ? "LEFT JOIN (SELECT code, MAX(frequency) AS frequency, MAX(row_colour) AS row_colour FROM dd_plant GROUP BY code) dp ON dp.code = a.code"
    : "LEFT JOIN (SELECT code, MAX(frequency) AS frequency FROM dd_plant GROUP BY code) dp ON dp.code = a.code";
$rowColourSelect = $hasPlantRowColour ? "COALESCE(dp.row_colour, '') AS row_colour" : "'' AS row_colour";
$conditionSql = "a.`condition`";
$dueDateSearchSql = "DATE_FORMAT(FROM_UNIXTIME(NULLIF(a.duedate, 0)), '%d-%m-%Y')";
$manufactureDateSearchSql = "(CASE WHEN a.dateofmanf REGEXP '^[0-9]{10}$' THEN DATE_FORMAT(FROM_UNIXTIME(a.dateofmanf), '%d-%m-%Y') ELSE a.dateofmanf END)";

if ($mode === 'all') {
    $offset = max(0, enrep_request_int('offset'));
    $perPage = max(1, min(1000, enrep_request_int('limit', 250)));
} else {
    $offset = ($page - 1) * $perPage;
}

$sortMap = [
    'itemnumber' => 'a.itemnumber',
    'description' => 'a.`desc`',
    'manufacturer' => 'a.manf',
    'make_model' => 'a.model',
    'model' => 'a.model',
    'condition' => $conditionSql,
    'plantnumber' => 'a.plantnumber',
    'serialnumber' => "COALESCE(CAST(a.serialnumber AS CHAR), '')",
    'location' => 'b.locname',
    'locname' => 'b.locname',
    'subloc' => 'a.subloc',
    'postcode' => 'b.postcode',
    'result' => 'a.lastReport',
    'lastReport' => 'a.lastReport',
    'duedate' => 'a.duedate'
];

$orderSql = $sortMap[$sortField] ?? 'a.duedate';
$orderBy = " ORDER BY {$orderSql} {$sortDir}, a.itemnumber ASC ";
if ($orderSql === 'a.duedate') {
    $orderBy = "
        ORDER BY
            CASE WHEN a.duedate IS NULL OR a.duedate = 0 THEN 1 ELSE 0 END ASC,
            a.duedate {$sortDir},
            a.itemnumber ASC
    ";
}

[$assignedSurveyorScopeSql, $assignedSurveyorScopeTypes, $assignedSurveyorScopeParams] = assetGridAssignedSurveyorScopeClause();

$totalWhere = "a.clientnumber = ? AND a.statuslive = ?{$assignedSurveyorScopeSql}";
$totalParams = array_merge([$client, $status], $assignedSurveyorScopeParams);
$totalTypes = 'ii' . $assignedSurveyorScopeTypes;

$where = $totalWhere;
$params = $totalParams;
$types = $totalTypes;

switch ($statusFilter) {
    case 'overdue':
        $where .= " AND a.duedate IS NOT NULL AND a.duedate <> 0 AND a.duedate < UNIX_TIMESTAMP()";
        break;
    case 'pending':
        $where .= " AND a.duedate IS NOT NULL AND a.duedate <> 0 AND a.duedate >= UNIX_TIMESTAMP() AND a.duedate < (UNIX_TIMESTAMP() + 30*24*3600)";
        break;
    case 'not_due':
        $where .= " AND a.duedate IS NOT NULL AND a.duedate <> 0 AND a.duedate >= (UNIX_TIMESTAMP() + 30*24*3600)";
        break;
}

$searchColumns = [
    'CAST(a.itemnumber AS CHAR)',
    'a.plantnumber',
    'a.serialnumber',
    'a.`desc`',
    'a.manf',
    'a.model',
    $conditionSql,
    'a.subloc',
    'a.lastReport',
    'b.locname',
    'b.postcode',
    'b.locaddress1',
    'b.locaddress2',
    'b.locaddress3',
    'b.locaddress4',
    $dueDateSearchSql,
    $manufactureDateSearchSql
];

$terms = assetGridSearchTerms($searchRaw);
foreach ($terms as $term) {
    $likeTerm = assetGridLikeTerm($term);
    $termWhere = [];
    $termParams = [];

    if (preg_match('/^\d{2}-\d{2}-\d{4}$/', $term)) {
        $dt = DateTime::createFromFormat('d-m-Y', $term);
        if ($dt instanceof DateTime) {
            $startTs = (int)$dt->setTime(0, 0, 0)->format('U');
            $endTs = $startTs + 86399;
            $termWhere[] = 'a.duedate BETWEEN ? AND ?';
            $termParams[] = $startTs;
            $termParams[] = $endTs;
        }
    }

    if (preg_match('/^C\d+$/i', $term)) {
        $termWhere[] = "LOWER(CONCAT('C', SUBSTRING_INDEX(a.linked, ':', 1))) = LOWER(?)";
        $termParams[] = $term;
    }

    if (strtolower($term) === 'n/e') {
        $termWhere[] = "TRIM(COALESCE(a.lastReport, '')) = ''";
    }

    if (strtolower($term) === 'nds') {
        $termWhere[] = "(a.duedate IS NULL OR a.duedate = 0)";
    }

    foreach ($searchColumns as $columnSql) {
        $termWhere[] = "LOWER(COALESCE(CAST({$columnSql} AS CHAR), '')) LIKE CONCAT('%', LOWER(?), '%') ESCAPE '\\\\'";
        $termParams[] = $likeTerm;
    }

    if (!empty($termWhere)) {
        $where .= " AND (" . implode("\n        OR ", $termWhere) . ")";
        foreach ($termParams as $termParam) {
            $params[] = $termParam;
            $types .= is_int($termParam) ? 'i' : 's';
        }
    }
}

$recordsTotal = 0;
$stmt = $con->prepare("SELECT COUNT(*) FROM itemdetails a WHERE {$totalWhere}");
if ($stmt) {
    assetGridBindParams($stmt, $totalTypes, $totalParams);
    $stmt->execute();
    $stmt->bind_result($recordsTotal);
    $stmt->fetch();
    $stmt->close();
}

$recordsFiltered = 0;
$sqlCount = "
    SELECT COUNT(*)
    FROM itemdetails a
    LEFT JOIN locations b ON b.locnumber = a.locnumber
    WHERE {$where}
";
$stmt = $con->prepare($sqlCount);
if (!$stmt) {
    echo json_encode([
        'success' => false,
        'message' => 'Unable to load the asset schedule',
        'recordsTotal' => (int)$recordsTotal,
        'recordsFiltered' => 0,
        'data' => []
    ]);
    exit;
}
assetGridBindParams($stmt, $types, $params);
$stmt->execute();
$stmt->bind_result($recordsFiltered);
$stmt->fetch();
$stmt->close();

$sql = "
    SELECT
        a.itemnumber,
        a.clientnumber,
        a.plantnumber,
        a.`desc` AS description,
        a.serialnumber,
        a.model,
        a.manf,
        a.dateofmanf,
        a.swl,
        b.locname,
        a.locnumber,
        a.subloc,
        b.postcode,
        b.locaddress1,
        b.locaddress2,
        b.locaddress3,
        b.locaddress4,
        a.code,
        {$conditionSql} AS asset_condition,
        a.lastReport,
        a.linked,
        a.duedate,
        COALESCE(dp.frequency, '') AS frequency,
        {$rowColourSelect},
        CASE WHEN CHAR_LENGTH(TRIM(COALESCE(a.itemnotes, ''))) > 0 THEN 1 ELSE 0 END AS has_item_notes,
        CASE WHEN CHAR_LENGTH(TRIM(COALESCE(b.locnotes, ''))) > 0 THEN 1 ELSE 0 END AS has_loc_notes,
        0 AS ws_id,
        '' AS ws_no,
        0 AS ws_renewal,
        0 AS lws_id,
        '' AS lws_no,
        0 AS puwer_set_id,
        '' AS puwer_set_title
    FROM itemdetails a
    LEFT JOIN locations b ON b.locnumber = a.locnumber
    {$ddPlantJoin}
    WHERE {$where}
    {$orderBy}
    LIMIT ?, ?
";

$paramsPage = $params;
$paramsPage[] = $offset;
$paramsPage[] = $perPage;
$typesPage = $types . 'ii';

$stmt = $con->prepare($sql);
if (!$stmt) {
    echo json_encode([
        'success' => false,
        'message' => 'Unable to load the asset schedule',
        'recordsTotal' => (int)$recordsTotal,
        'recordsFiltered' => (int)$recordsFiltered,
        'data' => []
    ]);
    exit;
}

assetGridBindParams($stmt, $typesPage, $paramsPage);
$stmt->execute();
$res = $stmt->get_result();

$rows = [];
while ($r = $res->fetch_assoc()) {
    $rows[] = [
        'itemnumber' => (int)($r['itemnumber'] ?? 0),
        'clientnumber' => (int)($r['clientnumber'] ?? 0),
        'plantnumber' => (string)($r['plantnumber'] ?? ''),
        'description' => (string)($r['description'] ?? ''),
        'serialnumber' => (string)($r['serialnumber'] ?? ''),
        'model' => (string)($r['model'] ?? ''),
        'manf' => (string)($r['manf'] ?? ''),
        'system_type' => '',
        'asset_condition' => (string)($r['asset_condition'] ?? ''),
        'dateofmanf' => (string)($r['dateofmanf'] ?? ''),
        'swl' => (string)($r['swl'] ?? ''),
        'locname' => (string)($r['locname'] ?? ''),
        'locnumber' => (int)($r['locnumber'] ?? 0),
        'subloc' => (string)($r['subloc'] ?? ''),
        'postcode' => (string)($r['postcode'] ?? ''),
        'locaddress1' => (string)($r['locaddress1'] ?? ''),
        'locaddress2' => (string)($r['locaddress2'] ?? ''),
        'locaddress3' => (string)($r['locaddress3'] ?? ''),
        'locaddress4' => (string)($r['locaddress4'] ?? ''),
        'code' => (string)($r['code'] ?? ''),
        'lastReport' => (string)($r['lastReport'] ?? ''),
        'pna_streak' => 0,
        'linked' => (string)($r['linked'] ?? ''),
        'duedate' => ($r['duedate'] !== null && $r['duedate'] !== '') ? (int)$r['duedate'] : 0,
        'frequency' => (string)($r['frequency'] ?? ''),
        'row_colour' => (string)($r['row_colour'] ?? ''),
        'has_item_notes' => (int)($r['has_item_notes'] ?? 0),
        'has_loc_notes' => (int)($r['has_loc_notes'] ?? 0),
        'ws_id' => (int)($r['ws_id'] ?? 0),
        'ws_no' => (string)($r['ws_no'] ?? ''),
        'ws_renewal' => (int)($r['ws_renewal'] ?? 0),
        'lws_id' => (int)($r['lws_id'] ?? 0),
        'lws_no' => (string)($r['lws_no'] ?? ''),
        'puwer_set_id' => (int)($r['puwer_set_id'] ?? 0),
        'puwer_set_title' => (string)($r['puwer_set_title'] ?? ''),
    ];
}
$stmt->close();

$pnaItemnumbers = [];
$pageItemnumbers = [];
foreach ($rows as $row) {
    $pageItemnumbers[] = (int)($row['itemnumber'] ?? 0);
    if (strtoupper(trim((string)($row['lastReport'] ?? ''))) === 'PNA') {
        $pnaItemnumbers[] = (int)($row['itemnumber'] ?? 0);
    }
}

$schemeBadges = assetGridFetchSchemeBadges($con, $pageItemnumbers);
if (!empty($schemeBadges)) {
    foreach ($rows as &$row) {
        $itemnumber = (int)($row['itemnumber'] ?? 0);
        if (!isset($schemeBadges[$itemnumber])) {
            continue;
        }

        $row['ws_id'] = (int)($schemeBadges[$itemnumber]['ws_id'] ?? 0);
        $row['ws_no'] = (string)($schemeBadges[$itemnumber]['ws_no'] ?? '');
        $row['ws_renewal'] = (int)($schemeBadges[$itemnumber]['ws_renewal'] ?? 0);
        $row['lws_id'] = (int)($schemeBadges[$itemnumber]['lws_id'] ?? 0);
        $row['lws_no'] = (string)($schemeBadges[$itemnumber]['lws_no'] ?? '');
    }
    unset($row);
}

$puwerBadges = assetGridFetchPuwerBadges($con, $client, $pageItemnumbers);
if (!empty($puwerBadges)) {
    foreach ($rows as &$row) {
        $itemnumber = (int)($row['itemnumber'] ?? 0);
        if (!isset($puwerBadges[$itemnumber])) {
            continue;
        }

        $row['puwer_set_id'] = (int)($puwerBadges[$itemnumber]['puwer_set_id'] ?? 0);
        $row['puwer_set_title'] = (string)($puwerBadges[$itemnumber]['puwer_set_title'] ?? '');
    }
    unset($row);
}

$pnaStreaks = assetGridFetchPnaStreaks($con, $client, $pnaItemnumbers);
if (!empty($pnaStreaks)) {
    foreach ($rows as &$row) {
        $itemnumber = (int)($row['itemnumber'] ?? 0);
        $row['pna_streak'] = (int)($pnaStreaks[$itemnumber] ?? 0);
    }
    unset($row);
}

echo json_encode([
    'success' => true,
    'total' => (int)$recordsTotal,
    'filtered' => (int)$recordsFiltered,
    'rows' => $rows,
    'recordsTotal' => (int)$recordsTotal,
    'recordsFiltered' => (int)$recordsFiltered,
    'data' => $rows,
    'page' => $page,
    'perPage' => $perPage,
    'nextOffset' => $offset + count($rows),
    'hasMore' => ($offset + count($rows)) < (int)$recordsFiltered
], JSON_INVALID_UTF8_SUBSTITUTE);
