<?php
// save_appliance_job.php
require_once 'includes/auth.php';
require_role(['admin', 'inspector'], true);

header('Content-Type: application/json');
require_once 'db.php';
require_once 'includes/activity_log.php';

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);
        exit;
    }

    require_csrf();

    $applianceId = $_POST['appliance_id'] ?? null;
    $jobId = $_POST['job_id'] ?? null;

    if (!$jobId && !$applianceId) {
        echo json_encode(['status' => 'error', 'message' => 'Missing Job ID and Appliance ID.']);
        exit;
    }

    // CRITICAL FIX: same class of bug as view_job.php — this file had NO
    // Is_Locked check at all. An approved/locked certificate could be
    // silently re-edited via a direct POST, defeating the entire Approve
    // & Lock feature. The UI hiding the form is not a security boundary;
    // this is.
    if ($jobId) {
        $lockCheck = $pdo->prepare("SELECT Is_Locked FROM tbl_jobs WHERE ID = ?");
        $lockCheck->execute([$jobId]);
        $lockRow = $lockCheck->fetch(PDO::FETCH_ASSOC);
        if (!$lockRow) {
            echo json_encode(['status' => 'error', 'message' => 'Job not found.']);
            exit;
        }
        if ((int) $lockRow['Is_Locked'] === 1) {
            echo json_encode(['status' => 'error', 'message' => 'This certificate is approved and locked. An Admin must unlock it before it can be edited.']);
            exit;
        }
    }

    // Collect form fields
    $itemName             = $_POST['ItemName'] ?? '';
    $serialNo             = $_POST['Serial_No'] ?? '';
    $brand                = $_POST['brand'] ?? '';
    $model                = $_POST['model'] ?? '';
    $itemNameDescription  = $_POST['item_name_description'] ?? '';
    $itemDescription      = $_POST['item_description'] ?? '';
    $certificateTitle     = $_POST['Certificate_Title'] ?? '';
    $approvalStatus       = $_POST['Approval_Status'] ?? 'Pass';
    $testParams           = $_POST['test_params'] ?? [];
    $chkResults           = $_POST['checklist_results'] ?? [];
    $chkRemarks           = $_POST['checklist_remarks'] ?? [];

    // New certificate note fields (shared with the LLG/general job form)
    $equipmentUsed  = trim($_POST['equipment_used'] ?? '');
    $colourCode     = trim($_POST['colour_code'] ?? '');
    $deviations     = $_POST['deviations'] ?? '';
    $subcontracted  = $_POST['subcontracted'] ?? '';
    $comments       = $_POST['comments'] ?? '';
    $prevInspection = $_POST['previous_inspection_details'] ?? '';

    // FIX (docx item 2): Work Order Ref is set once at job creation
    // (add_job.php) and must stay immutable after that — it links the
    // certificate to the client's accounting record and should never drift.
    // This handler used to accept and write it from POST on every save; the
    // write path is removed entirely (not just hidden client-side) so a
    // direct/tampered POST can't change it either. Same immutability
    // treatment as Job No.

    $pdo->beginTransaction();

    // BUG FIX ("where did the field I set disappear to?"): tbl_jobs.Item_Name
    // (shown on the dashboard/job list and used for checklist matching) and
    // tbl_appliance_inspections.ItemName (this form's own "Item Name" field)
    // are two separate columns for the same real-world value. They used to
    // drift apart silently: this handler only ever wrote the Appliance-side
    // column, so clearing this field and saving would leave tbl_jobs.Item_Name
    // untouched but poison this column with '' — which then broke every
    // `??`-based fallback reading it (edit form, certificate heading). Keep
    // the two in sync in both directions:
    //   - a real (non-blank) value here becomes the job's Item Name too, so
    //     the dashboard and checklist matching immediately reflect it;
    //   - a blank submission does NOT overwrite a perfectly good existing
    //     Item Name with '' — it re-reads and reuses the job's current value
    //     instead, so this field self-heals back to it on next load rather
    //     than staying empty.
    if ($jobId) {
        if ($itemName !== '') {
            $pdo->prepare("UPDATE tbl_jobs SET Item_Name = ? WHERE ID = ?")->execute([$itemName, $jobId]);
        } else {
            $jobItemNameStmt = $pdo->prepare("SELECT Item_Name FROM tbl_jobs WHERE ID = ?");
            $jobItemNameStmt->execute([$jobId]);
            $itemName = trim((string) ($jobItemNameStmt->fetchColumn() ?: ''));
        }
    }

    // NEW (docx items 1 & 3): Site Name / Sub Location / Type of Inspection are
    // shared job-level fields (apply to every category, not just Appliance/Mis),
    // so they live on tbl_jobs itself and are persisted here exactly like
    // Item_Name above.
    if ($jobId) {
        $siteIdRaw   = $_POST['site_id'] ?? '';
        $siteId      = ($siteIdRaw === '' || $siteIdRaw === '0') ? null : (int) $siteIdRaw;
        $subLocation = trim($_POST['sub_location'] ?? '');

        $allowedInspectionTypes = [
            'In-Service Thorough Examination',
            'Pre-Use Inspection',
            'Initial Examination',
            'Periodic Examination',
            'Exceptional Examination',
            'Visual Inspection',
            'Proof Load Testing',
            'Maintenance Inspection',
        ];
        $inspectionType = trim($_POST['inspection_type'] ?? '');
        if (!in_array($inspectionType, $allowedInspectionTypes, true)) {
            $inspectionType = 'In-Service Thorough Examination';
        }

        // Anti-IDOR: only accept a Site_ID that actually belongs to this job's
        // own client, so a tampered request can't attach another client's site.
        if ($siteId !== null) {
            $siteCheck = $pdo->prepare('SELECT cs.SiteID FROM tbl_client_sites cs
                INNER JOIN tbl_jobs j ON j.ClientID = cs.ClientID
                WHERE cs.SiteID = ? AND j.ID = ? AND cs.Deleted_At IS NULL LIMIT 1');
            $siteCheck->execute([$siteId, $jobId]);
            if (!$siteCheck->fetchColumn()) {
                $siteId = null;
            }
        }

        $pdo->prepare('UPDATE tbl_jobs SET Site_ID = ?, Sub_Location = ?, Inspection_Type = ? WHERE ID = ?')
            ->execute([$siteId, $subLocation, $inspectionType, $jobId]);
    }

    // If Appliance ID is missing or empty, find or create it using Job ID
    if (empty($applianceId) || $applianceId === 'null') {
        $stmtCheck = $pdo->prepare("SELECT Appliance_ID FROM tbl_appliance_inspections WHERE JobID = ?");
        $stmtCheck->execute([$jobId]);
        $row = $stmtCheck->fetch(PDO::FETCH_ASSOC);

        if ($row) {
            $applianceId = $row['Appliance_ID'];
        } else {
            $stmtIns = $pdo->prepare("INSERT INTO tbl_appliance_inspections (JobID, ItemName) VALUES (?, ?)");
            $stmtIns->execute([$jobId, $itemName]);
            $applianceId = $pdo->lastInsertId();
        }
    }

    // 1. Update main inspection details
    $stmtUpdate = $pdo->prepare("UPDATE tbl_appliance_inspections SET
        ItemName = ?,
        Serial_No = ?,
        brand = ?,
        model = ?,
        item_name_description = ?,
        item_description = ?,
        Certificate_Title = ?,
        Approval_Status = ?,
        Equipment_Used = ?,
        Colour_Code = ?,
        Deviations = ?,
        Subcontracted = ?,
        Comments = ?,
        Previous_Inspection_Details = ?
        WHERE Appliance_ID = ?");

    $stmtUpdate->execute([
        $itemName,
        $serialNo,
        $brand,
        $model,
        $itemNameDescription,
        $itemDescription,
        $certificateTitle,
        $approvalStatus,
        $equipmentUsed,
        $colourCode,
        $deviations,
        $subcontracted,
        $comments,
        $prevInspection,
        $applianceId
    ]);

    // 2. Refresh Test Parameters (Delete existing rows for this inspection and re-insert)
    $stmtDeleteParams = $pdo->prepare("DELETE FROM tbl_appliance_test_parameters WHERE inspection_id = ?");
    $stmtDeleteParams->execute([$applianceId]);

    $stmtInsertParam = $pdo->prepare("INSERT INTO tbl_appliance_test_parameters
        (inspection_id, `row_number`, boom_length, radius, tested_load, safe_working_load)
        VALUES (?, ?, ?, ?, ?, ?)");

    foreach ($testParams as $rowNum => $rowDat) {
        $boomLength = $rowDat['boom_length'] ?? '';
        $radius     = $rowDat['radius'] ?? '';
        $testedLoad = $rowDat['tested_load'] ?? '';
        $swl        = $rowDat['safe_working_load'] ?? '';

        // Only insert if at least one parameter field has data
        if (!empty($boomLength) || !empty($radius) || !empty($testedLoad) || !empty($swl)) {
            $stmtInsertParam->execute([
                $applianceId,
                $rowNum,
                $boomLength,
                $radius,
                $testedLoad,
                $swl
            ]);
        }
    }

    // 3. Save / Update Checklist Results in tbl_job_checklists
    foreach ($chkResults as $masterCheckID => $resultVal) {
        $remarkVal = $chkRemarks[$masterCheckID] ?? '';

        // Check if a record already exists for this Job ID and MasterCheckID
        $checkExist = $pdo->prepare("SELECT ChecklistID FROM tbl_job_checklists WHERE JobID = ? AND MasterCheckID = ?");
        $checkExist->execute([$jobId, $masterCheckID]);
        $existingId = $checkExist->fetchColumn();

        if ($existingId) {
            $updChk = $pdo->prepare("UPDATE tbl_job_checklists SET Result = ?, Remarks = ?, Updated_At = NOW() WHERE ChecklistID = ?");
            $updChk->execute([$resultVal, $remarkVal, $existingId]);
        } else {
            $insChk = $pdo->prepare("INSERT INTO tbl_job_checklists (JobID, MasterCheckID, Result, Remarks, Updated_At) VALUES (?, ?, ?, ?, NOW())");
            $insChk->execute([$jobId, $masterCheckID, $resultVal, $remarkVal]);
        }
    }

    $pdo->commit();
    logActivity($pdo, (int) $jobId, 'edited', 'Appliance inspection and checklist updated');
    echo json_encode(['status' => 'success', 'message' => 'Appliance inspection details and checklists saved successfully!']);

} catch (\Throwable $e) {
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    // SECURITY FIX: this used to echo the raw exception message (potential
    // DB schema/query/path disclosure) straight into the JSON response —
    // violates this project's "never expose raw DB errors" rule. Logged
    // server-side only now; the client gets a safe generic message.
    error_log('save_appliance_job.php error: ' . $e->getMessage());
    echo json_encode(['status' => 'error', 'message' => 'A server error occurred while saving. Please try again or contact support.']);
}
?>
