<?php

// ============================================================
// ATTENDANCE CHECKOUT API
// File: api/attendance_checkout.php
//
// Method: POST - multipart/form-data
//
// Required:
// user_id (STRING, e.g. EMP001, HR01, MD01, SUPER01)
// latitude
// longitude
// photo
//
// Optional:
// location_address
//
// Supported Roles:
// employee
// manager
// hr
// md
// superadmin
//
// Flow:
// 1. Validate user
// 2. Validate allowed role
// 3. Validate GPS
// 4. Check today's attendance
// 5. Must already be checked in
// 6. Prevent duplicate checkout
// 7. Employee/Manager must complete evening responsibilities
// 8. HR/MD/Superadmin can checkout without responsibility check
// 9. Validate and save checkout photo
// 10. Save logout GPS
// 11. Save logout_time
// 12. Calculate daily working minutes/hours
// 13. Update daily_reports.daily_working_hours
// 14. Recalculate monthly working hours
// 15. Insert/update monthly_working_hours
// 16. Update employee_live_locations if table exists
//
// NOTE:
// This system was migrated from INTEGER user IDs to STRING
// user IDs (VARCHAR(30) PRIMARY KEY), e.g. EMP001, BS01, HR01.
// user_id is NEVER cast to int, NEVER compared numerically,
// and is ALWAYS bound as a string ("s") in prepared statements.
// ============================================================

header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

date_default_timezone_set('Asia/Kolkata');

// ============================================================
// OPTIONS
// ============================================================

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {

    http_response_code(200);

    exit();
}

// ============================================================
// DATABASE CONNECTION
// ============================================================

require_once '../config.php';

// ============================================================
// RESPONSE FUNCTION
// ============================================================

function sendResponse(
    int $statusCode,
    bool $success,
    string $message,
    array $extra = []
): void {

    http_response_code(
        $statusCode
    );

    echo json_encode(
        array_merge(
            [
                "success" =>
                    $success,

                "message" =>
                    $message
            ],
            $extra
        ),
        JSON_UNESCAPED_UNICODE |
        JSON_UNESCAPED_SLASHES
    );

    exit();
}

// ============================================================
// ONLY POST
// ============================================================

if (
    $_SERVER[
        'REQUEST_METHOD'
    ] !== 'POST'
) {

    sendResponse(
        405,
        false,
        "Only POST method is allowed."
    );
}

// ============================================================
// INPUT
//
// user_id is a STRING identifier (e.g. EMP001, HR01, MD01).
// It is never cast to (int) and never treated numerically.
// ============================================================

$userId =
    trim(
        $_POST[
            'user_id'
        ] ?? ''
    );

$latitude =
    trim(
        $_POST[
            'latitude'
        ] ?? ''
    );

$longitude =
    trim(
        $_POST[
            'longitude'
        ] ?? ''
    );

$locationAddress =
    trim(
        $_POST[
            'location_address'
        ] ?? ''
    );

// ============================================================
// VALIDATE USER ID
//
// Must be a non-empty string. Length and charset are checked
// to match the VARCHAR(30) column, without assuming any
// numeric format.
// ============================================================

if (
    $userId === ''
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Valid user_id is required."
    );
}

if (strlen($userId) > 30) {

    $conn->close();

    sendResponse(
        400,
        false,
        "user_id must not exceed 30 characters."
    );
}

if (!preg_match('/^[A-Za-z0-9_\-]+$/', $userId)) {

    $conn->close();

    sendResponse(
        400,
        false,
        "user_id contains invalid characters."
    );
}

// ============================================================
// VALIDATE GPS
// ============================================================

if (
    $latitude === ''
    ||
    $longitude === ''
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Current GPS location is required for checkout."
    );
}

if (
    !is_numeric(
        $latitude
    )
    ||
    !is_numeric(
        $longitude
    )
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Invalid latitude or longitude."
    );
}

$latitudeFloat =
    (float)$latitude;

$longitudeFloat =
    (float)$longitude;

// ============================================================
// LATITUDE RANGE
// ============================================================

if (
    $latitudeFloat < -90
    ||
    $latitudeFloat > 90
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Invalid latitude."
    );
}

// ============================================================
// LONGITUDE RANGE
// ============================================================

if (
    $longitudeFloat < -180
    ||
    $longitudeFloat > 180
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Invalid longitude."
    );
}

// ============================================================
// CURRENT DATE / TIME
// ============================================================

$today =
    date(
        'Y-m-d'
    );

$logoutTime =
    date(
        'Y-m-d H:i:s'
    );

$currentYear =
    (int)date(
        'Y'
    );

$currentMonth =
    (int)date(
        'n'
    );

// ============================================================
// VALIDATE USER
//
// users.id is VARCHAR(30) PRIMARY KEY, bound as string.
// ============================================================

$stmt =
    $conn->prepare("
        SELECT
            id,
            username,
            role
        FROM users
        WHERE id = ?
        LIMIT 1
    ");

if (!$stmt) {

    $conn->close();

    sendResponse(
        500,
        false,
        "Unable to validate user."
    );
}

$stmt->bind_param(
    "s",
    $userId
);

$stmt->execute();

$result =
    $stmt->get_result();

if (
    $result->num_rows === 0
) {

    $stmt->close();

    $conn->close();

    sendResponse(
        404,
        false,
        "User not found."
    );
}

$user =
    $result->fetch_assoc();

$stmt->close();

// ============================================================
// NORMALIZE ROLE
// ============================================================

$role =
    strtolower(
        trim(
            $user[
                'role'
            ] ?? ''
        )
    );

// ============================================================
// ALLOWED ROLES
// ============================================================

$allowedRoles = [
    'employee',
    'manager',
    'hr',
    'md',
    'superadmin'
];

if (
    !in_array(
        $role,
        $allowedRoles,
        true
    )
) {

    $conn->close();

    sendResponse(
        403,
        false,
        "Your account is not allowed to use attendance checkout."
    );
}

// ============================================================
// GET TODAY ATTENDANCE
//
// user_id bound as string ("s"), never numeric.
// ============================================================

$stmt =
    $conn->prepare("
        SELECT
            id,
            login_time,
            logout_time,
            daily_working_hours
        FROM daily_reports
        WHERE user_id = ?
          AND report_date = ?
        ORDER BY id DESC
        LIMIT 1
    ");

if (!$stmt) {

    $conn->close();

    sendResponse(
        500,
        false,
        "Unable to verify today's attendance."
    );
}

$stmt->bind_param(
    "ss",
    $userId,
    $today
);

$stmt->execute();

$result =
    $stmt->get_result();

// ============================================================
// NO ATTENDANCE RECORD
// ============================================================

if (
    $result->num_rows === 0
) {

    $stmt->close();

    $conn->close();

    sendResponse(
        403,
        false,
        "You have not checked in today."
    );
}

$attendance =
    $result->fetch_assoc();

$stmt->close();

$dailyReportId =
    (int)$attendance[
        'id'
    ];

// ============================================================
// CHECK LOGIN TIME
// ============================================================

if (
    empty(
        $attendance[
            'login_time'
        ]
    )
) {

    $conn->close();

    sendResponse(
        403,
        false,
        "You have not checked in today."
    );
}

// ============================================================
// PREVENT DUPLICATE CHECKOUT
// ============================================================

if (
    !empty(
        $attendance[
            'logout_time'
        ]
    )
) {

    $conn->close();

    sendResponse(
        409,
        false,
        "You have already checked out today.",
        [

            "attendance" => [

                "daily_report_id" =>
                    (string)$dailyReportId,

                "user_id" =>
                    $userId,

                "username" =>
                    $user[
                        'username'
                    ],

                "role" =>
                    $role,

                "report_date" =>
                    $today,

                "login_time" =>
                    $attendance[
                        'login_time'
                    ],

                "logout_time" =>
                    $attendance[
                        'logout_time'
                    ],

                "daily_working_hours" =>
                    (float)(
                        $attendance[
                            'daily_working_hours'
                        ] ?? 0
                    ),

                "has_checked_in" =>
                    true,

                "has_checked_out" =>
                    true,

                "attendance_status" =>
                    "checked_out"
            ]
        ]
    );
}

// ============================================================
// RESPONSIBILITY SUMMARY DEFAULT
// ============================================================

$totalResponsibilities =
    0;

$completedResponsibilities =
    0;

// ============================================================
// RESPONSIBILITY CHECK
//
// Employee and Manager:
// Must complete evening responsibilities.
//
// HR / MD / Superadmin:
// Their own attendance does not require employee
// responsibility completion.
// ============================================================

$responsibilityRequiredRoles = [
    'employee',
    'manager'
];

if (
    in_array(
        $role,
        $responsibilityRequiredRoles,
        true
    )
) {

    // ========================================================
    // CHECK RESPONSIBILITY COMPLETION
    //
    // user_id bound as string ("s") wherever it appears.
    // ========================================================

    $stmt =
        $conn->prepare("
            SELECT

                COUNT(
                    DISTINCT dr.id
                ) AS total_responsibilities,

                COUNT(
                    DISTINCT
                    CASE
                        WHEN
                            dru.evening_completed = 1
                        THEN
                            dr.id
                    END
                ) AS completed_responsibilities

            FROM daily_responsibilities dr

            LEFT JOIN
                daily_responsibility_updates dru

                ON
                    dru.responsibility_id =
                    dr.id

                AND
                    dru.user_id =
                    dr.user_id

                AND
                    dru.report_date = ?

            WHERE
                dr.user_id = ?

            AND
                dr.is_active = 1

            AND
            (
                dr.start_date IS NULL
                OR
                dr.start_date <= ?
            )

            AND
            (
                dr.end_date IS NULL
                OR
                dr.end_date >= ?
            )
        ");

    if (!$stmt) {

        $conn->close();

        sendResponse(
            500,
            false,
            "Unable to verify daily responsibilities."
        );
    }

    $stmt->bind_param(
        "ssss",
        $today,
        $userId,
        $today,
        $today
    );

    $stmt->execute();

    $result =
        $stmt->get_result();

    $responsibilitySummary =
        $result->fetch_assoc();

    $stmt->close();

    $totalResponsibilities =
        (int)(
            $responsibilitySummary[
                'total_responsibilities'
            ] ?? 0
        );

    $completedResponsibilities =
        (int)(
            $responsibilitySummary[
                'completed_responsibilities'
            ] ?? 0
        );

    // ========================================================
    // BLOCK CHECKOUT IF RESPONSIBILITIES INCOMPLETE
    // ========================================================

    if (
        $totalResponsibilities > 0
        &&
        $completedResponsibilities <
            $totalResponsibilities
    ) {

        $remaining =
            $totalResponsibilities -
            $completedResponsibilities;

        $conn->close();

        sendResponse(
            403,
            false,
            "Please complete all end-of-day responsibility updates before checkout.",
            [

                "responsibility_summary" => [

                    "total" =>
                        $totalResponsibilities,

                    "completed" =>
                        $completedResponsibilities,

                    "remaining" =>
                        $remaining
                ]
            ]
        );
    }
}

// ============================================================
// VALIDATE CHECKOUT PHOTO
// ============================================================

if (
    !isset(
        $_FILES[
            'photo'
        ]
    )
    ||
    $_FILES[
        'photo'
    ][
        'error'
    ] !== UPLOAD_ERR_OK
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Checkout photo is required."
    );
}

$photo =
    $_FILES[
        'photo'
    ];

// ============================================================
// VALIDATE TEMP UPLOAD
// ============================================================

if (
    empty(
        $photo[
            'tmp_name'
        ]
    )
    ||
    !is_uploaded_file(
        $photo[
            'tmp_name'
        ]
    )
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Invalid uploaded checkout photo."
    );
}

// ============================================================
// MAXIMUM PHOTO SIZE 10 MB
// ============================================================

$maxFileSize =
    10 *
    1024 *
    1024;

if (
    $photo[
        'size'
    ] > $maxFileSize
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Photo size must be less than 10 MB."
    );
}

// ============================================================
// VALIDATE IMAGE MIME TYPE
// ============================================================

$finfo =
    new finfo(
        FILEINFO_MIME_TYPE
    );

$mimeType =
    $finfo->file(
        $photo[
            'tmp_name'
        ]
    );

$allowedMimeTypes = [

    'image/jpeg' =>
        'jpg',

    'image/png' =>
        'png',

    'image/webp' =>
        'webp'
];

if (
    !isset(
        $allowedMimeTypes[
            $mimeType
        ]
    )
) {

    $conn->close();

    sendResponse(
        400,
        false,
        "Only JPG, PNG and WEBP images are allowed."
    );
}

$extension =
    $allowedMimeTypes[
        $mimeType
    ];

// ============================================================
// CHECKOUT PHOTO DIRECTORY
// ============================================================

$uploadRelativeDirectory =
    'uploads/attendance/' .
    date(
        'Y'
    ) .
    '/' .
    date(
        'm'
    ) .
    '/';

$uploadAbsoluteDirectory =
    dirname(
        __DIR__
    ) .
    '/' .
    $uploadRelativeDirectory;

// ============================================================
// CREATE DIRECTORY
// ============================================================

if (
    !is_dir(
        $uploadAbsoluteDirectory
    )
) {

    if (
        !mkdir(
            $uploadAbsoluteDirectory,
            0755,
            true
        )
        &&
        !is_dir(
            $uploadAbsoluteDirectory
        )
    ) {

        $conn->close();

        sendResponse(
            500,
            false,
            "Unable to create attendance photo directory."
        );
    }
}

// ============================================================
// UNIQUE FILE NAME
//
// The string user_id (e.g. EMP001) is sanitized for filesystem
// safety before being embedded in the file name.
// ============================================================

try {

    $randomString =
        bin2hex(
            random_bytes(
                8
            )
        );

} catch (
    Throwable $e
) {

    $randomString =
        uniqid(
            '',
            true
        );
}

$safeUserIdForFileName =
    preg_replace(
        '/[^A-Za-z0-9_\-]/',
        '_',
        $userId
    );

$fileName =
    'checkout_' .
    $safeUserIdForFileName .
    '_' .
    date(
        'Ymd_His'
    ) .
    '_' .
    $randomString .
    '.' .
    $extension;

$absoluteFilePath =
    $uploadAbsoluteDirectory .
    $fileName;

$databasePhotoPath =
    $uploadRelativeDirectory .
    $fileName;

// ============================================================
// SAVE PHOTO
// ============================================================

if (
    !move_uploaded_file(
        $photo[
            'tmp_name'
        ],
        $absoluteFilePath
    )
) {

    $conn->close();

    sendResponse(
        500,
        false,
        "Unable to save checkout photo."
    );
}

// ============================================================
// CALCULATE DAILY WORKING TIME
// ============================================================

$loginTimestamp =
    strtotime(
        $attendance[
            'login_time'
        ]
    );

$logoutTimestamp =
    strtotime(
        $logoutTime
    );

if (
    $loginTimestamp === false
    ||
    $logoutTimestamp === false
) {

    if (
        file_exists(
            $absoluteFilePath
        )
    ) {

        @unlink(
            $absoluteFilePath
        );
    }

    $conn->close();

    sendResponse(
        500,
        false,
        "Unable to calculate working hours."
    );
}

// ============================================================
// ENSURE LOGOUT IS AFTER LOGIN
// ============================================================

if (
    $logoutTimestamp <
    $loginTimestamp
) {

    if (
        file_exists(
            $absoluteFilePath
        )
    ) {

        @unlink(
            $absoluteFilePath
        );
    }

    $conn->close();

    sendResponse(
        500,
        false,
        "Invalid attendance time. Checkout time cannot be earlier than check-in time."
    );
}

// ============================================================
// WORKING SECONDS
// ============================================================

$workingSeconds =
    $logoutTimestamp -
    $loginTimestamp;

// ============================================================
// WORKING MINUTES
// ============================================================

$dailyWorkingMinutes =
    (int)floor(
        $workingSeconds /
        60
    );

// ============================================================
// DECIMAL WORKING HOURS
//
// 8h 30m = 8.50
// 8h 45m = 8.75
// ============================================================

$dailyWorkingHours =
    round(
        $dailyWorkingMinutes /
        60,
        2
    );

// ============================================================
// DISPLAY FORMAT
// ============================================================

$displayHours =
    intdiv(
        $dailyWorkingMinutes,
        60
    );

$displayMinutes =
    $dailyWorkingMinutes %
    60;

$dailyWorkingDisplay =
    sprintf(
        '%02dh %02dm',
        $displayHours,
        $displayMinutes
    );

// ============================================================
// START TRANSACTION
// ============================================================

$conn->begin_transaction();

try {

    // ========================================================
    // UPDATE DAILY REPORT
    //
    // Correct bind types:
    //
    // s logout_time
    // d logout_latitude
    // d logout_longitude
    // s logout_photo_path
    // d daily_working_hours
    // i daily_report_id       (daily_reports.id, still int PK)
    // s user_id               (users.id, VARCHAR(30))
    //
    // Type string:
    // sddsdis
    // ========================================================

    $stmt =
        $conn->prepare("
            UPDATE daily_reports
            SET
                logout_time = ?,
                logout_latitude = ?,
                logout_longitude = ?,
                logout_photo_path = ?,
                daily_working_hours = ?
            WHERE id = ?
              AND user_id = ?
              AND logout_time IS NULL
        ");

    if (!$stmt) {

        throw new Exception(
            "Unable to prepare attendance checkout update."
        );
    }

    $stmt->bind_param(
        "sddsdis",
        $logoutTime,
        $latitudeFloat,
        $longitudeFloat,
        $databasePhotoPath,
        $dailyWorkingHours,
        $dailyReportId,
        $userId
    );

    if (
        !$stmt->execute()
    ) {

        $error =
            $stmt->error;

        $stmt->close();

        throw new Exception(
            "Unable to complete checkout. " .
            $error
        );
    }

    if (
        $stmt->affected_rows === 0
    ) {

        $stmt->close();

        throw new Exception(
            "Checkout could not be completed or attendance was already checked out."
        );
    }

    $stmt->close();

    // ========================================================
    // MONTH START / END
    // ========================================================

    $monthStart =
        date(
            'Y-m-01'
        );

    $monthEnd =
        date(
            'Y-m-t'
        );

    // ========================================================
    // RECALCULATE MONTHLY TOTAL
    //
    // Always calculate from daily_reports.
    // Prevents duplicate total-hour additions.
    // user_id bound as string ("s").
    // ========================================================

    $stmt =
        $conn->prepare("
            SELECT

                COALESCE(
                    SUM(
                        daily_working_hours
                    ),
                    0
                ) AS total_hours,

                COUNT(
                    CASE

                        WHEN
                            login_time IS NOT NULL

                        AND
                            logout_time IS NOT NULL

                        THEN 1

                    END
                ) AS total_days

            FROM daily_reports

            WHERE user_id = ?

              AND report_date
                    BETWEEN ? AND ?

              AND daily_working_hours
                    IS NOT NULL
        ");

    if (!$stmt) {

        throw new Exception(
            "Unable to calculate monthly working hours."
        );
    }

    $stmt->bind_param(
        "sss",
        $userId,
        $monthStart,
        $monthEnd
    );

    $stmt->execute();

    $result =
        $stmt->get_result();

    $monthlyData =
        $result->fetch_assoc();

    $stmt->close();

    // ========================================================
    // MONTHLY TOTAL HOURS
    // ========================================================

    $totalWorkingHours =
        round(
            (float)(
                $monthlyData[
                    'total_hours'
                ] ?? 0
            ),
            2
        );

    // ========================================================
    // MONTHLY TOTAL MINUTES
    // ========================================================

    $totalWorkingMinutes =
        (int)round(
            $totalWorkingHours *
            60
        );

    // ========================================================
    // MONTHLY TOTAL DAYS
    // ========================================================

    $totalWorkingDays =
        (int)(
            $monthlyData[
                'total_days'
            ] ?? 0
        );

    // ========================================================
    // INSERT / UPDATE MONTHLY WORKING HOURS
    //
    // IMPORTANT:
    // monthly_working_hours should have UNIQUE KEY:
    // (user_id, year, month)
    //
    // user_id column here is also VARCHAR(30), bound as
    // string ("s"). year/month remain integers ("i").
    // ========================================================

    $stmt =
        $conn->prepare("
            INSERT INTO monthly_working_hours
            (
                user_id,
                year,
                month,
                total_working_hours,
                total_working_minutes,
                total_working_days
            )

            VALUES
            (
                ?,
                ?,
                ?,
                ?,
                ?,
                ?
            )

            ON DUPLICATE KEY UPDATE

                total_working_hours =
                    VALUES(
                        total_working_hours
                    ),

                total_working_minutes =
                    VALUES(
                        total_working_minutes
                    ),

                total_working_days =
                    VALUES(
                        total_working_days
                    )
        ");

    if (!$stmt) {

        throw new Exception(
            "Unable to prepare monthly working hours update."
        );
    }

    $stmt->bind_param(
        "siidii",
        $userId,
        $currentYear,
        $currentMonth,
        $totalWorkingHours,
        $totalWorkingMinutes,
        $totalWorkingDays
    );

    if (
        !$stmt->execute()
    ) {

        $error =
            $stmt->error;

        $stmt->close();

        throw new Exception(
            "Unable to update monthly working hours. " .
            $error
        );
    }

    $stmt->close();

    // ========================================================
    // UPDATE LIVE LOCATION IF TABLE EXISTS
    //
    // user_id bound as string ("s").
    // ========================================================

    $tableCheck =
        $conn->query("
            SHOW TABLES
            LIKE 'employee_live_locations'
        ");

    if (
        $tableCheck
        &&
        $tableCheck->num_rows > 0
    ) {

        $stmt =
            $conn->prepare("
                INSERT INTO employee_live_locations
                (
                    user_id,
                    latitude,
                    longitude,
                    location_address,
                    last_updated
                )

                VALUES
                (
                    ?,
                    ?,
                    ?,
                    ?,
                    NOW()
                )

                ON DUPLICATE KEY UPDATE

                    latitude =
                        VALUES(
                            latitude
                        ),

                    longitude =
                        VALUES(
                            longitude
                        ),

                    location_address =
                        VALUES(
                            location_address
                        ),

                    last_updated =
                        NOW()
            ");

        if ($stmt) {

            $stmt->bind_param(
                "sdds",
                $userId,
                $latitudeFloat,
                $longitudeFloat,
                $locationAddress
            );

            $stmt->execute();

            $stmt->close();
        }
    }

    // ========================================================
    // COMMIT TRANSACTION
    // ========================================================

    $conn->commit();

    // ========================================================
    // SUCCESS RESPONSE DATA
    // ========================================================

    $responseData = [

        "attendance" => [

            "daily_report_id" =>
                (string)$dailyReportId,

            "user_id" =>
                $userId,

            "username" =>
                $user[
                    'username'
                ],

            "role" =>
                $role,

            "report_date" =>
                $today,

            "login_time" =>
                $attendance[
                    'login_time'
                ],

            "logout_time" =>
                $logoutTime,

            "daily_working_hours" =>
                $dailyWorkingHours,

            "daily_working_minutes" =>
                $dailyWorkingMinutes,

            "daily_working_display" =>
                $dailyWorkingDisplay,

            "logout_latitude" =>
                $latitudeFloat,

            "logout_longitude" =>
                $longitudeFloat,

            "location_address" =>
                $locationAddress,

            "logout_photo_path" =>
                $databasePhotoPath,

            "has_checked_in" =>
                true,

            "has_checked_out" =>
                true,

            "attendance_status" =>
                "checked_out"
        ],

        "responsibilities" => [

            "required" =>
                in_array(
                    $role,
                    $responsibilityRequiredRoles,
                    true
                ),

            "total" =>
                $totalResponsibilities,

            "completed" =>
                $completedResponsibilities,

            "remaining" =>
                max(
                    0,
                    $totalResponsibilities -
                    $completedResponsibilities
                )
        ],

        "monthly_working_hours" => [

            "year" =>
                $currentYear,

            "month" =>
                $currentMonth,

            "month_name" =>
                date(
                    'F'
                ),

            "total_working_hours" =>
                $totalWorkingHours,

            "total_working_minutes" =>
                $totalWorkingMinutes,

            "total_working_days" =>
                $totalWorkingDays
        ]
    ];

    // ========================================================
    // CLOSE DATABASE
    // ========================================================

    $conn->close();

    // ========================================================
    // SUCCESS
    // ========================================================

    sendResponse(
        200,
        true,
        "Attendance checkout successful.",
        $responseData
    );

} catch (
    Throwable $e
) {

    // ========================================================
    // ROLLBACK DATABASE
    // ========================================================

    $conn->rollback();

    // ========================================================
    // DELETE CHECKOUT PHOTO
    // IF DATABASE TRANSACTION FAILED
    // ========================================================

    if (
        isset(
            $absoluteFilePath
        )
        &&
        file_exists(
            $absoluteFilePath
        )
    ) {

        @unlink(
            $absoluteFilePath
        );
    }

    $conn->close();

    // ========================================================
    // ERROR RESPONSE
    // ========================================================

    sendResponse(
        500,
        false,
        $e->getMessage()
    );
}

?>