<?php

// ============================================================
// ATTENDANCE CHECK-IN API
// File: api/attendance_checkin.php
//
// Method:
// POST - multipart/form-data
//
// Required:
// user_id (STRING, e.g. EMP001, HR01, MD01, SUPER01)
// latitude
// longitude
// photo
//
// Optional:
// location_type
// location_address
// client_name
//
// Supported Roles:
// employee
// manager
// hr
// md
// superadmin
//
// Saves:
// daily_reports.report_date
// daily_reports.login_time
// daily_reports.latitude
// daily_reports.longitude
// daily_reports.location_type
// daily_reports.location_address
// daily_reports.client_name
// daily_reports.photo_path
//
// Also:
// - Prevents duplicate daily check-in
// - Saves check-in photo
// - Updates 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 REQUEST
// ============================================================

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 ALLOWED
// ============================================================

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

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

// ============================================================
// GET MULTIPART 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'] ?? ''
);

$locationType = trim(
    $_POST['location_type'] ?? ''
);

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

$clientName = trim(
    $_POST['client_name'] ?? ''
);

// ============================================================
// VALIDATE USER ID
//
// Must be a non-empty string. Optionally enforce a sane max
// length / charset to match VARCHAR(30) column and avoid
// unexpected input, 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 LOCATION
// ============================================================

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

    $conn->close();

    sendResponse(
        400,
        false,
        "Current GPS location is required for attendance check-in."
    );
}

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

    $conn->close();

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

$latitudeFloat =
    (float)$latitude;

$longitudeFloat =
    (float)$longitude;

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

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

    $conn->close();

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

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

    $conn->close();

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

// ============================================================
// 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 FOR OWN ATTENDANCE
// ============================================================

$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 check-in."
    );
}

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

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

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

// ============================================================
// CHECK EXISTING TODAY RECORD
//
// user_id bound as string ("s"), never numeric.
// ============================================================

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

if (!$stmt) {

    $conn->close();

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

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

$stmt->execute();

$result =
    $stmt->get_result();

$existingReport =
    null;

if (
    $result->num_rows > 0
) {

    $existingReport =
        $result->fetch_assoc();
}

$stmt->close();

// ============================================================
// PREVENT DUPLICATE CHECK-IN
// ============================================================

if (
    $existingReport &&
    !empty(
        $existingReport[
            'login_time'
        ]
    )
) {

    $conn->close();

    sendResponse(
        409,
        false,
        "You have already checked in today.",
        [
            "attendance" => [

                "daily_report_id" =>
                    (string)$existingReport[
                        'id'
                    ],

                "user_id" =>
                    $userId,

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

                "role" =>
                    $role,

                "report_date" =>
                    $today,

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

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

                "has_checked_in" =>
                    true,

                "has_checked_out" =>
                    !empty(
                        $existingReport[
                            'logout_time'
                        ]
                    )
            ]
        ]
    );
}

// ============================================================
// VALIDATE CHECK-IN PHOTO
// ============================================================

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

    $conn->close();

    sendResponse(
        400,
        false,
        "Check-in photo is required."
    );
}

$photo =
    $_FILES['photo'];

// ============================================================
// VALIDATE FILE SIZE
// MAXIMUM 10 MB
// ============================================================

$maxFileSize =
    10 * 1024 * 1024;

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

    $conn->close();

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

// ============================================================
// VALIDATE TEMP FILE
// ============================================================

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

    $conn->close();

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

// ============================================================
// VALIDATE ACTUAL 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
    ];

// ============================================================
// CREATE UPLOAD DIRECTORY
//
// PHP:
// /api/attendance_checkin.php
//
// Upload:
// /uploads/attendance/YYYY/MM/
// ============================================================

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

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

if (
    !is_dir(
        $uploadAbsoluteDirectory
    )
) {

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

        $conn->close();

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

// ============================================================
// GENERATE SAFE 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 =
    'checkin_' .
    $safeUserIdForFileName .
    '_' .
    date('Ymd_His') .
    '_' .
    $randomString .
    '.' .
    $extension;

$absoluteFilePath =
    $uploadAbsoluteDirectory .
    $fileName;

$databasePhotoPath =
    $uploadRelativeDirectory .
    $fileName;

// ============================================================
// MOVE UPLOADED PHOTO
// ============================================================

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

    $conn->close();

    sendResponse(
        500,
        false,
        "Unable to save check-in photo."
    );
}

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

$conn->begin_transaction();

try {

    $dailyReportId =
        null;

    // ========================================================
    // EXISTING DAILY REPORT
    //
    // A row may already exist because another daily process
    // created it before attendance check-in.
    // ========================================================

    if ($existingReport) {

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

        // daily_reports.id remains an auto-increment integer
        // primary key for the report row itself; only user_id
        // (a foreign key to users.id) is treated as a string.

        $stmt = $conn->prepare("
            UPDATE daily_reports
            SET
                login_time = ?,
                latitude = ?,
                longitude = ?,
                location_type = ?,
                location_address = ?,
                client_name = ?,
                photo_path = ?
            WHERE id = ?
              AND user_id = ?
        ");

        if (!$stmt) {

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

        $stmt->bind_param(
            "sddsssiss",
            $loginTime,
            $latitudeFloat,
            $longitudeFloat,
            $locationType,
            $locationAddress,
            $clientName,
            $databasePhotoPath,
            $dailyReportId,
            $userId
        );

        // NOTE: daily_reports.id remains a genuine integer
        // primary key ("i"), while user_id is bound as a
        // string ("s") since users.id is VARCHAR(30).

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

            $error =
                $stmt->error;

            $stmt->close();

            throw new Exception(
                $error
            );
        }

        $stmt->close();

    } else {

        // ====================================================
        // CREATE NEW DAILY REPORT
        //
        // user_id is inserted as a string foreign key value.
        // ====================================================

        $stmt = $conn->prepare("
            INSERT INTO daily_reports
            (
                user_id,
                report_date,
                login_time,
                latitude,
                longitude,
                location_type,
                location_address,
                client_name,
                photo_path
            )
            VALUES
            (
                ?,
                ?,
                ?,
                ?,
                ?,
                ?,
                ?,
                ?,
                ?
            )
        ");

        if (!$stmt) {

            throw new Exception(
                "Unable to prepare attendance check-in."
            );
        }

        $stmt->bind_param(
            "sssddssss",
            $userId,
            $today,
            $loginTime,
            $latitudeFloat,
            $longitudeFloat,
            $locationType,
            $locationAddress,
            $clientName,
            $databasePhotoPath
        );

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

            $error =
                $stmt->error;

            $stmt->close();

            throw new Exception(
                $error
            );
        }

        $dailyReportId =
            $conn->insert_id;

        $stmt->close();
    }

    // ========================================================
    // UPDATE LIVE LOCATION TABLE
    //
    // This runs only if employee_live_locations exists.
    // user_id is bound as a string here as well.
    // ========================================================

    $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
    // ========================================================

    $conn->commit();

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

    $responseData = [

        "attendance" => [

            "daily_report_id" =>
                (string)$dailyReportId,

            "user_id" =>
                $userId,

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

            "role" =>
                $role,

            "report_date" =>
                $today,

            "login_time" =>
                $loginTime,

            "logout_time" =>
                null,

            "latitude" =>
                $latitudeFloat,

            "longitude" =>
                $longitudeFloat,

            "location_type" =>
                $locationType,

            "location_address" =>
                $locationAddress,

            "client_name" =>
                $clientName,

            "photo_path" =>
                $databasePhotoPath,

            "has_checked_in" =>
                true,

            "has_checked_out" =>
                false,

            "attendance_status" =>
                "checked_in"
        ]
    ];

    $conn->close();

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

    sendResponse(
        200,
        true,
        "Attendance check-in successful.",
        $responseData
    );

} catch (
    Throwable $e
) {

    // ========================================================
    // ROLLBACK
    // ========================================================

    $conn->rollback();

    // ========================================================
    // DELETE UPLOADED PHOTO IF DATABASE FAILED
    // ========================================================

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

        @unlink(
            $absoluteFilePath
        );
    }

    $conn->close();

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

    sendResponse(
        500,
        false,
        "Unable to complete attendance check-in."
    );
}

?>