<?php

date_default_timezone_set('Asia/Colombo');

require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../includes/csrf.php';
require_once __DIR__ . '/../includes/role_filter.php';
require_once __DIR__ . '/../includes/activity_log.php';

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

function redirectUpdateError(int $surveyId, string $message): void
{
    $_SESSION['error_message'] = $message;

    header(
        'Location: edit_survey.php?id=' .
        urlencode((string)$surveyId)
    );

    exit();
}

function updatePostValue(string $key, int $maxLength = 255): string
{
    $value = trim((string)($_POST[$key] ?? ''));

    if (mb_strlen($value) > $maxLength) {
        throw new RuntimeException(
            'One or more submitted fields are too long.'
        );
    }

    return $value;
}

function updateQuantity(mixed $value): int
{
    $quantity = filter_var(
        $value,
        FILTER_VALIDATE_INT,
        ['options' => ['min_range' => 0]]
    );

    if ($quantity === false) {
        throw new RuntimeException(
            'Equipment quantities must be whole numbers equal to or greater than zero.'
        );
    }

    return $quantity;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: view_surveys.php');
    exit();
}

$surveyId = filter_var(
    $_POST['id'] ?? null,
    FILTER_VALIDATE_INT,
    ['options' => ['min_range' => 1]]
);

if (!$surveyId) {
    http_response_code(400);
    exit('Invalid survey ID.');
}

if (
    !hash_equals(
        $_SESSION['csrf_token'] ?? '',
        $_POST['csrf_token'] ?? ''
    )
) {
    redirectUpdateError(
        $surveyId,
        'Invalid security token. Please refresh the page and try again.'
    );
}

$roleFilter = getSurveyRoleFilter('s');

$accessSql = '
    SELECT
        s.id,
        s.census_no,
        s.school_name,
        s.zone_name,
        s.entered_by
    FROM surveys s
    WHERE s.id = ?
    ' . $roleFilter['sql'] . '
    LIMIT 1
';

$accessStatement = mysqli_prepare($conn, $accessSql);

$accessTypes = 'i' . $roleFilter['types'];
$accessParams = array_merge([$surveyId], $roleFilter['params']);

mysqli_stmt_bind_param(
    $accessStatement,
    $accessTypes,
    ...$accessParams
);

mysqli_stmt_execute($accessStatement);

$accessResult = mysqli_stmt_get_result($accessStatement);
$currentSurvey = mysqli_fetch_assoc($accessResult);

mysqli_stmt_close($accessStatement);

if (!$currentSurvey) {
    http_response_code(404);
    exit('Survey not found or access denied.');
}

try {
    $principalName = updatePostValue('principal_name');
    $principalPhone = updatePostValue('principal_phone', 20);
    $schoolPhone = updatePostValue('school_phone', 20);
    $itTeacherName = updatePostValue('it_teacher_name');
    $itTeacherPhone = updatePostValue('it_teacher_phone', 20);

    $surveyDetails = json_decode(
        (string)($_POST['survey_details'] ?? ''),
        true,
        512,
        JSON_THROW_ON_ERROR
    );

    if (!is_array($surveyDetails) || $surveyDetails === []) {
        throw new RuntimeException(
            'At least one equipment record is required.'
        );
    }
} catch (Throwable $exception) {
    redirectUpdateError(
        $surveyId,
        $exception->getMessage()
    );
}

/*
|--------------------------------------------------------------------------
| Load allowed fixed unit/equipment assignments
|--------------------------------------------------------------------------
*/

$allowedStandardEquipment = [];

$allowedStatement = mysqli_prepare(
    $conn,
    "SELECT
        um.unit_name,
        em.id AS equipment_id
     FROM unit_master um
     INNER JOIN unit_equipment ue
        ON ue.unit_id = um.id
       AND ue.status = 'Active'
     INNER JOIN equipment_master em
        ON em.id = ue.equipment_id
       AND em.status = 'Active'
     WHERE um.status = 'Active'
       AND um.is_required = 'Yes'"
);

mysqli_stmt_execute($allowedStatement);
$allowedResult = mysqli_stmt_get_result($allowedStatement);

while ($row = mysqli_fetch_assoc($allowedResult)) {
    $unitName = trim((string)$row['unit_name']);
    $equipmentId = (int)$row['equipment_id'];

    if (!isset($allowedStandardEquipment[$unitName])) {
        $allowedStandardEquipment[$unitName] = [];
    }

    $allowedStandardEquipment[$unitName][$equipmentId] = true;
}

mysqli_stmt_close($allowedStatement);

$transactionStarted = false;

try {
    mysqli_begin_transaction($conn);
    $transactionStarted = true;

    /*
    |--------------------------------------------------------------------------
    | Lock survey row and re-check permission
    |--------------------------------------------------------------------------
    */

    $lockSql = '
        SELECT s.id
        FROM surveys s
        WHERE s.id = ?
        ' . $roleFilter['sql'] . '
        LIMIT 1
        FOR UPDATE
    ';

    $lockStatement = mysqli_prepare($conn, $lockSql);

    $lockTypes = 'i' . $roleFilter['types'];
    $lockParams = array_merge([$surveyId], $roleFilter['params']);

    mysqli_stmt_bind_param(
        $lockStatement,
        $lockTypes,
        ...$lockParams
    );

    mysqli_stmt_execute($lockStatement);

    $lockResult = mysqli_stmt_get_result($lockStatement);

    if (!mysqli_fetch_assoc($lockResult)) {
        throw new RuntimeException(
            'Survey not found or access denied.'
        );
    }

    mysqli_stmt_close($lockStatement);

    /*
    |--------------------------------------------------------------------------
    | Update survey contacts
    |--------------------------------------------------------------------------
    */

    $headerStatement = mysqli_prepare(
        $conn,
        'UPDATE surveys
         SET
            principal_name = ?,
            principal_phone = ?,
            school_phone = ?,
            it_teacher_name = ?,
            it_teacher_phone = ?
         WHERE id = ?'
    );

    mysqli_stmt_bind_param(
        $headerStatement,
        'sssssi',
        $principalName,
        $principalPhone,
        $schoolPhone,
        $itTeacherName,
        $itTeacherPhone,
        $surveyId
    );

    mysqli_stmt_execute($headerStatement);
    mysqli_stmt_close($headerStatement);

    /*
    |--------------------------------------------------------------------------
    | Replace saved detail rows
    |--------------------------------------------------------------------------
    */

    $deleteFixed = mysqli_prepare(
        $conn,
        'DELETE FROM survey_equipment_details
         WHERE survey_id = ?'
    );

    mysqli_stmt_bind_param($deleteFixed, 'i', $surveyId);
    mysqli_stmt_execute($deleteFixed);
    mysqli_stmt_close($deleteFixed);

    $deleteOtherEquipment = mysqli_prepare(
        $conn,
        'DELETE soe
         FROM survey_other_equipment soe
         INNER JOIN survey_other_units sou
            ON sou.id = soe.other_unit_id
         WHERE sou.survey_id = ?'
    );

    mysqli_stmt_bind_param(
        $deleteOtherEquipment,
        'i',
        $surveyId
    );

    mysqli_stmt_execute($deleteOtherEquipment);
    mysqli_stmt_close($deleteOtherEquipment);

    $deleteOtherUnits = mysqli_prepare(
        $conn,
        'DELETE FROM survey_other_units
         WHERE survey_id = ?'
    );

    mysqli_stmt_bind_param(
        $deleteOtherUnits,
        'i',
        $surveyId
    );

    mysqli_stmt_execute($deleteOtherUnits);
    mysqli_stmt_close($deleteOtherUnits);

    /*
    |--------------------------------------------------------------------------
    | Prepare inserts
    |--------------------------------------------------------------------------
    */

    $standardInsert = mysqli_prepare(
        $conn,
        'INSERT INTO survey_equipment_details
        (
            survey_id,
            section,
            equipment_id,
            working,
            not_working,
            repair
        )
        VALUES (?, ?, ?, ?, ?, ?)'
    );

    $otherUnitInsert = mysqli_prepare(
        $conn,
        'INSERT INTO survey_other_units
        (
            survey_id,
            unit_name,
            details,
            display_order
        )
        VALUES (?, ?, ?, ?)'
    );

    $otherEquipmentInsert = mysqli_prepare(
        $conn,
        'INSERT INTO survey_other_equipment
        (
            other_unit_id,
            equipment_name,
            working,
            not_working,
            repair,
            display_order
        )
        VALUES (?, ?, ?, ?, ?, ?)'
    );

    $savedCount = 0;
    $otherUnitOrder = 1;
    $submittedStandard = [];
    $submittedUnitNames = [];

    foreach ($surveyDetails as $unit) {
        if (!is_array($unit)) {
            throw new RuntimeException('Invalid unit details.');
        }

        $section = trim((string)($unit['section'] ?? ''));
        $isCustom = filter_var(
            $unit['is_custom'] ?? false,
            FILTER_VALIDATE_BOOLEAN
        );

        $equipmentItems = $unit['equipment'] ?? [];

        if (
            $section === '' ||
            mb_strlen($section) > 150 ||
            !is_array($equipmentItems)
        ) {
            throw new RuntimeException('Invalid unit details.');
        }

        $normalizedSection = mb_strtolower($section);

        if (isset($submittedUnitNames[$normalizedSection])) {
            throw new RuntimeException(
                'Duplicate unit: ' . $section . '.'
            );
        }

        $submittedUnitNames[$normalizedSection] = true;

        if ($isCustom) {
            if ($equipmentItems === []) {
                throw new RuntimeException(
                    'Please add equipment to ' . $section . '.'
                );
            }

            $details = trim((string)($unit['details'] ?? ''));

            if (mb_strlen($details) > 5000) {
                throw new RuntimeException(
                    'Other-unit details are too long.'
                );
            }

            mysqli_stmt_bind_param(
                $otherUnitInsert,
                'issi',
                $surveyId,
                $section,
                $details,
                $otherUnitOrder
            );

            mysqli_stmt_execute($otherUnitInsert);

            $otherUnitId = mysqli_insert_id($conn);

            if ($otherUnitId <= 0) {
                throw new RuntimeException(
                    'Unable to save ' . $section . '.'
                );
            }

            $equipmentOrder = 1;
            $equipmentNames = [];

            foreach ($equipmentItems as $item) {
                if (!is_array($item)) {
                    throw new RuntimeException(
                        'Invalid equipment details.'
                    );
                }

                $equipmentName = trim(
                    (string)($item['equipment_name'] ?? '')
                );

                if (
                    $equipmentName === '' ||
                    mb_strlen($equipmentName) > 150
                ) {
                    throw new RuntimeException(
                        'Enter a valid equipment name in ' .
                        $section .
                        '.'
                    );
                }

                $normalizedName = mb_strtolower($equipmentName);

                if (isset($equipmentNames[$normalizedName])) {
                    throw new RuntimeException(
                        'Duplicate equipment "' .
                        $equipmentName .
                        '" in ' .
                        $section .
                        '.'
                    );
                }

                $equipmentNames[$normalizedName] = true;

                $working = updateQuantity(
                    $item['working'] ?? null
                );

                $notWorking = updateQuantity(
                    $item['not_working'] ?? null
                );

                $repair = updateQuantity(
                    $item['repair'] ?? null
                );

                mysqli_stmt_bind_param(
                    $otherEquipmentInsert,
                    'isiiii',
                    $otherUnitId,
                    $equipmentName,
                    $working,
                    $notWorking,
                    $repair,
                    $equipmentOrder
                );

                mysqli_stmt_execute($otherEquipmentInsert);

                $equipmentOrder++;
                $savedCount++;
            }

            $otherUnitOrder++;
            continue;
        }

        if (!isset($allowedStandardEquipment[$section])) {
            throw new RuntimeException(
                'Invalid standard unit: ' . $section . '.'
            );
        }

        foreach ($equipmentItems as $item) {
            if (!is_array($item)) {
                throw new RuntimeException(
                    'Invalid equipment details.'
                );
            }

            $equipmentId = filter_var(
                $item['equipment_id'] ?? null,
                FILTER_VALIDATE_INT,
                ['options' => ['min_range' => 1]]
            );

            if (
                $equipmentId === false ||
                !isset(
                    $allowedStandardEquipment[
                        $section
                    ][$equipmentId]
                )
            ) {
                throw new RuntimeException(
                    'Invalid equipment in ' .
                    $section .
                    '.'
                );
            }

            $standardKey =
                $section . ':' . $equipmentId;

            if (isset($submittedStandard[$standardKey])) {
                throw new RuntimeException(
                    'Duplicate standard equipment in ' .
                    $section .
                    '.'
                );
            }

            $submittedStandard[$standardKey] = true;

            $working = updateQuantity(
                $item['working'] ?? null
            );

            $notWorking = updateQuantity(
                $item['not_working'] ?? null
            );

            $repair = updateQuantity(
                $item['repair'] ?? null
            );

            mysqli_stmt_bind_param(
                $standardInsert,
                'isiiii',
                $surveyId,
                $section,
                $equipmentId,
                $working,
                $notWorking,
                $repair
            );

            mysqli_stmt_execute($standardInsert);

            $savedCount++;
        }
    }

    mysqli_stmt_close($standardInsert);
    mysqli_stmt_close($otherUnitInsert);
    mysqli_stmt_close($otherEquipmentInsert);

    if ($savedCount === 0) {
        throw new RuntimeException(
            'At least one equipment record is required.'
        );
    }

    mysqli_commit($conn);
    $transactionStarted = false;

    logActivity(
        $conn,
        'Survey Management',
        'Update Survey',
        'Survey updated for "' .
        (string)$currentSurvey['school_name'] .
        '" (Census No: ' .
        (string)$currentSurvey['census_no'] .
        ')'
    );

    $_SESSION['success_message'] =
        'Survey updated successfully.';

    header(
        'Location: view_survey.php?id=' .
        urlencode((string)$surveyId)
    );

    exit();
} catch (Throwable $exception) {
    if ($transactionStarted) {
        mysqli_rollback($conn);
    }

    error_log(
        'Survey update error: ' .
        $exception->getMessage()
    );

    $message = $exception->getMessage();

    if (
        str_starts_with($message, 'Invalid ') ||
        str_starts_with($message, 'Duplicate ') ||
        str_starts_with($message, 'Please ') ||
        str_starts_with($message, 'Enter ') ||
        $message === 'At least one equipment record is required.' ||
        $message === 'Survey not found or access denied.'
    ) {
        redirectUpdateError($surveyId, $message);
    }

    redirectUpdateError(
        $surveyId,
        'Unable to update the survey. Please contact the administrator.'
    );
}