<?php
/**
 * SSBS-ISCMS — AJAX Login Endpoint
 * Returns JSON. Called from JavaScript when progressive enhancement is used.
 */
session_start();

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('X-Content-Type-Options: nosniff');

$response = ['success' => false, 'message' => ''];

// Only accept POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    $response['message'] = 'Method not allowed.';
    echo json_encode($response);
    exit();
}

// CSRF check
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
    !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
    http_response_code(403);
    $response['message'] = 'Invalid request token.';
    echo json_encode($response);
    exit();
}

// Already logged in
if (isset($_SESSION['user_id'])) {
    $response['success']      = true;
    $response['message']      = 'Already authenticated.';
    $response['redirect_url'] = 'index.php';
    echo json_encode($response);
    exit();
}

require_once 'layouts/dbconn.php';

$identifier = trim($_POST['identifier'] ?? '');
$password   = $_POST['password']   ?? '';

if (empty($identifier) || empty($password)) {
    $response['message'] = 'Email/username and password are required.';
    echo json_encode($response);
    exit();
}

$ip_address = filter_var(
    $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'],
    FILTER_VALIDATE_IP
) ?: $_SERVER['REMOTE_ADDR'];
$user_agent = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 500);

try {
    $sql = "SELECT u.id, u.org_id, u.role_id, u.dept_id, u.employee_number,
                   u.username, u.first_name, u.last_name, u.email,
                   u.password_hash, u.phone, u.user_type, u.designation,
                   u.profile_photo, u.status, u.email_verified,
                   u.failed_logins, u.locked_until,
                   u.must_change_password,
                   r.role_name, r.role_code,
                   d.dept_name, d.dept_code
            FROM   users u
            INNER JOIN roles       r ON u.role_id = r.id AND r.is_active = 1
            LEFT  JOIN departments d ON u.dept_id = d.id
            WHERE  (u.email = ? OR u.username = ?)
            LIMIT  1";

    $stmt = $conn->prepare($sql);
    $stmt->bind_param('ss', $identifier, $identifier);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows === 1) {
        $user = $result->fetch_assoc();

        // ── Status gate ──────────────────────────────────────────────────
        if ($user['status'] === 'inactive') {
            $response['message'] = 'Account deactivated. Contact the administrator.';
            echo json_encode($response);
            exit();
        }

        if ($user['status'] === 'pending_verification') {
            $response['message'] = 'Account pending verification. Check your email.';
            echo json_encode($response);
            exit();
        }

        if ($user['status'] === 'locked' ||
            ($user['locked_until'] !== null && strtotime($user['locked_until']) > time())) {
            $unlock_at = $user['locked_until']
                ? date('H:i', strtotime($user['locked_until']))
                : 'later';
            $response['message'] = "Account locked. Try again after {$unlock_at}.";
            $response['locked']  = true;
            echo json_encode($response);
            exit();
        }

        // ── Password verify ──────────────────────────────────────────────
        if (password_verify($password, $user['password_hash'])) {

            // Update login stamp
            $upd = $conn->prepare(
                "UPDATE users SET failed_logins = 0, locked_until = NULL,
                                  last_login = NOW(), last_ip = ?
                 WHERE id = ?"
            );
            $upd->bind_param('ss', $ip_address, $user['id']);
            $upd->execute();
            $upd->close();

            // Create user_sessions record
            $raw_token  = bin2hex(random_bytes(32));
            $token_hash = hash('sha256', $raw_token);

            $lifetime_h = 8;
            $cfg = $conn->query("SELECT setting_value FROM system_settings WHERE setting_key = 'session_lifetime_hours' LIMIT 1");
            if ($cfg && $row = $cfg->fetch_assoc()) {
                $lifetime_h = max(1, (int)$row['setting_value']);
            }
            $expires_at = date('Y-m-d H:i:s', strtotime("+{$lifetime_h} hours"));

            $ins = $conn->prepare(
                "INSERT INTO user_sessions (id, user_id, token_hash, ip_address, user_agent, expires_at)
                 VALUES (UUID(), ?, ?, ?, ?, ?)"
            );
            $ins->bind_param('sssss', $user['id'], $token_hash, $ip_address, $user_agent, $expires_at);
            $ins->execute();
            $ins->close();

            $sess_id = '';
            $sess_row = $conn->query(
                "SELECT id FROM user_sessions WHERE token_hash = '"
                . $conn->real_escape_string($token_hash) . "' LIMIT 1"
            );
            if ($sess_row) {
                $sess_id = $sess_row->fetch_assoc()['id'] ?? '';
            }

            // Audit log
            $log_data = json_encode([
                'event'      => 'LOGIN_SUCCESS',
                'role'       => $user['role_code'],
                'user_type'  => $user['user_type'],
                'session_id' => $sess_id,
            ]);
            $log = $conn->prepare(
                "INSERT INTO audit_logs
                   (id, user_id, session_id, action, module,
                    entity_type, entity_id, new_values,
                    ip_address, user_agent, request_method, request_path)
                 VALUES (UUID(), ?, ?, 'LOGIN', 'authentication',
                         'user', ?, ?, ?, ?, 'POST', '/login_process.php')"
            );
            $log->bind_param('ssssss',
                $user['id'], $sess_id,
                $user['id'], $log_data,
                $ip_address, $user_agent
            );
            $log->execute();
            $log->close();

            // Regenerate session ID
            session_regenerate_id(true);

            // Store session
            $_SESSION['user_id']         = $user['id'];
            $_SESSION['email']           = $user['email'];
            $_SESSION['username']        = $user['username'];
            $_SESSION['first_name']      = $user['first_name'];
            $_SESSION['last_name']       = $user['last_name'];
            $_SESSION['full_name']       = trim($user['first_name'] . ' ' . $user['last_name']);
            $_SESSION['phone']           = $user['phone'];
            $_SESSION['role_id']         = $user['role_id'];
            $_SESSION['role_name']       = $user['role_name'];
            $_SESSION['role_code']       = $user['role_code'];
            $_SESSION['user_type']       = $user['user_type'];
            $_SESSION['designation']     = $user['designation'];
            $_SESSION['dept_id']         = $user['dept_id'];
            $_SESSION['dept_name']       = $user['dept_name'];
            $_SESSION['dept_code']       = $user['dept_code'];
            $_SESSION['org_id']          = $user['org_id'];
            $_SESSION['employee_number'] = $user['employee_number'];
            $_SESSION['profile_photo']   = $user['profile_photo'];
            $_SESSION['login_time']      = time();
            $_SESSION['session_db_id']   = $sess_id;
            $_SESSION['session_token']   = $raw_token;
            $_SESSION['must_change_pw']  = (bool)$user['must_change_password'];

            $conn->close();

            $redirect = match($user['role_code']) {
                'SUPER_ADMIN'  => 'index.php',
                'ADMIN'        => 'index.php',
                'CERT_OFFICER' => 'certifications.php',
                'INSPECTOR'    => 'inspections.php',
                'LAB_OFFICER'  => 'laboratory.php',
                'ENF_OFFICER'  => 'enforcement.php',
                'MKT_OFFICER'  => 'market_surveillance.php',
                'STD_OFFICER'  => 'standards.php',
                'CLIENT'       => 'client_portal.php',
                'REVIEWER'     => 'applications.php',
                'FINANCE'      => 'finance.php',
                default        => 'index.php',
            };

            if ($user['must_change_password']) {
                $redirect = 'change_password.php?forced=1';
            }

            echo json_encode([
                'success'      => true,
                'message'      => 'Login successful.',
                'redirect_url' => $redirect,
                'user'         => [
                    'full_name'  => $_SESSION['full_name'],
                    'role_name'  => $user['role_name'],
                    'role_code'  => $user['role_code'],
                    'user_type'  => $user['user_type'],
                ],
            ]);

        } else {
            // Wrong password
            $new_fails = $user['failed_logins'] + 1;

            $max_attempts = 5;
            $cfg2 = $conn->query("SELECT setting_value FROM system_settings WHERE setting_key = 'max_login_attempts' LIMIT 1");
            if ($cfg2 && $r2 = $cfg2->fetch_assoc()) {
                $max_attempts = max(1, (int)$r2['setting_value']);
            }

            $lock_until = null;
            if ($new_fails >= $max_attempts) {
                $lockout_min = 30;
                $cfg3 = $conn->query("SELECT setting_value FROM system_settings WHERE setting_key = 'account_lockout_minutes' LIMIT 1");
                if ($cfg3 && $r3 = $cfg3->fetch_assoc()) {
                    $lockout_min = max(1, (int)$r3['setting_value']);
                }
                $lock_until = date('Y-m-d H:i:s', strtotime("+{$lockout_min} minutes"));
            }

            $upd2 = $conn->prepare("UPDATE users SET failed_logins = ?, locked_until = ? WHERE id = ?");
            $upd2->bind_param('iss', $new_fails, $lock_until, $user['id']);
            $upd2->execute();
            $upd2->close();

            $fail_data = json_encode([
                'event'    => 'LOGIN_FAILED',
                'reason'   => 'invalid_password',
                'attempts' => $new_fails,
            ]);
            $log2 = $conn->prepare(
                "INSERT INTO audit_logs
                   (id, user_id, action, module, entity_type, entity_id,
                    new_values, ip_address, user_agent, request_method, request_path)
                 VALUES (UUID(), ?, 'LOGIN_FAILED', 'authentication',
                         'user', ?, ?, ?, ?, 'POST', '/login_process.php')"
            );
            $log2->bind_param('sssss',
                $user['id'], $user['id'],
                $fail_data, $ip_address, $user_agent
            );
            $log2->execute();
            $log2->close();

            $remaining = max(0, $max_attempts - $new_fails);
            if ($lock_until) {
                $msg = 'Account locked due to too many failed attempts. Try again in 30 minutes.';
            } elseif ($remaining > 0) {
                $msg = "Invalid credentials. {$remaining} attempt(s) remaining.";
            } else {
                $msg = 'Invalid email/username or password.';
            }

            echo json_encode([
                'success'           => false,
                'message'           => $msg,
                'remaining_attempts'=> $remaining,
                'locked'            => ($lock_until !== null),
            ]);
        }

        $stmt->close();

    } else {
        // User not found
        $fail_data = json_encode(['event' => 'LOGIN_FAILED', 'reason' => 'user_not_found']);
        $log3 = $conn->prepare(
            "INSERT INTO audit_logs
               (id, action, module, new_values, ip_address, user_agent,
                request_method, request_path)
             VALUES (UUID(), 'LOGIN_FAILED', 'authentication',
                     ?, ?, ?, 'POST', '/login_process.php')"
        );
        $log3->bind_param('sss', $fail_data, $ip_address, $user_agent);
        $log3->execute();
        $log3->close();
        $stmt->close();

        echo json_encode(['success' => false, 'message' => 'Invalid email/username or password.']);
    }

    $conn->close();

} catch (Exception $e) {
    error_log('SSBS login_process error: ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'System error. Please try again.']);
}
