<?php
declare(strict_types=1);

/**
 * /public_html/test_erp/api/auth/login_action.php
 * Secure Login Action — TEST Environment
 * Updated: 2026-07-22
 */

require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/db.php';
require_once __DIR__ . '/../../config/response.php';
require_once __DIR__ . '/../_csrf_guard.php';

/*
|--------------------------------------------------------------------------
| Login Security Settings
|--------------------------------------------------------------------------
*/

if (!defined('ERP_LOGIN_MAX_FAILED_ATTEMPTS')) {
    define('ERP_LOGIN_MAX_FAILED_ATTEMPTS', 5);
}

if (!defined('ERP_LOGIN_LOCKOUT_MINUTES')) {
    define('ERP_LOGIN_LOCKOUT_MINUTES', 15);
}

/**
 * ব্যবহারকারীর IP address সংগ্রহ করে।
 */
function erp_login_client_ip(): string
{
    $sources = [
        'HTTP_CF_CONNECTING_IP',
        'REMOTE_ADDR',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_CLIENT_IP',
    ];

    foreach ($sources as $source) {
        if (empty($_SERVER[$source])) {
            continue;
        }

        $value = (string) $_SERVER[$source];
        $ip = trim(explode(',', $value)[0]);

        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            return $ip;
        }
    }

    return '0.0.0.0';
}

/**
 * Browser/User-Agent-এর নিরাপদ hash তৈরি করে।
 */
function erp_login_user_agent_hash(): string
{
    return hash(
        'sha256',
        (string) ($_SERVER['HTTP_USER_AGENT'] ?? '')
    );
}

/**
 * Login audit logger।
 *
 * Audit table-এ সমস্যা হলেও Login বন্ধ হবে না।
 * Password অথবা CSRF token কখনো log করা হবে না।
 */
function erp_login_safe_audit(
    $conn,
    int $userId,
    string $note
): void {
    try {
        if (!$conn) {
            return;
        }

        $ipAddress = erp_login_client_ip();

        $stmt = $conn->prepare(
            "
            INSERT INTO audit_log
                (
                    table_name,
                    record_id,
                    action,
                    changed_by,
                    changed_at,
                    ip_address,
                    note
                )
            VALUES
                (
                    'users',
                    ?,
                    'LOGIN',
                    ?,
                    NOW(),
                    ?,
                    ?
                )
            "
        );

        if (!$stmt) {
            return;
        }

        $stmt->bind_param(
            'iiss',
            $userId,
            $userId,
            $ipAddress,
            $note
        );

        $stmt->execute();
        $stmt->close();

    } catch (Throwable $exception) {
        // Audit error-এর কারণে Login বন্ধ হবে না।
    }
}

/*
|--------------------------------------------------------------------------
| শুধু POST Request গ্রহণ করা হবে
|--------------------------------------------------------------------------
*/

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    jsonResponse([
        'status'  => 405,
        'success' => false,
        'message' => 'শুধু POST অনুরোধ গ্রহণযোগ্য',
        'data'    => null,
    ], 405);
}

/*
|--------------------------------------------------------------------------
| Login Request-এর CSRF Verification
|--------------------------------------------------------------------------
*/

erp_csrf_required(true);

/*
|--------------------------------------------------------------------------
| Input গ্রহণ
|--------------------------------------------------------------------------
*/

$rawInput = file_get_contents('php://input');
$jsonInput = json_decode((string) $rawInput, true);

if (!is_array($jsonInput)) {
    $jsonInput = [];
}

$email = trim(
    (string) (
        $jsonInput['email']
        ?? $_POST['email']
        ?? ''
    )
);

$password = (string) (
    $jsonInput['password']
    ?? $_POST['password']
    ?? ''
);

if ($email === '' || $password === '') {
    jsonResponse([
        'status'  => 422,
        'success' => false,
        'message' => 'ইমেইল এবং পাসওয়ার্ড প্রয়োজন',
        'data'    => null,
    ], 422);
}

/*
|--------------------------------------------------------------------------
| User খোঁজা
|--------------------------------------------------------------------------
*/

$stmt = $conn->prepare(
    "
    SELECT
        id,
        name,
        email,
        password,
        role,
        status,
        failed_login_attempts,
        locked_until
    FROM users
    WHERE email = ?
    LIMIT 1
    "
);

if (!$stmt) {
    jsonResponse([
        'status'  => 500,
        'success' => false,
        'message' => 'সার্ভার সমস্যা হয়েছে',
        'data'    => null,
    ], 500);
}

$stmt->bind_param('s', $email);
$stmt->execute();

$result = $stmt->get_result();
$user = $result ? $result->fetch_assoc() : null;

$stmt->close();

/*
|--------------------------------------------------------------------------
| Email পাওয়া যায়নি
|--------------------------------------------------------------------------
*/

if (!$user) {
    password_verify(
        $password,
        '$2y$12$NgjAKOaUkKng.sigLrregeMSSZw4PERmCuXrNZIllwKPVXkBiYqm6'
    );

    erp_login_safe_audit(
        $conn,
        0,
        'Failed login: unknown account'
    );

    jsonResponse([
        'status'  => 401,
        'success' => false,
        'message' => 'ইমেইল বা পাসওয়ার্ড ভুল!',
        'data'    => null,
    ], 401);
}

$userId = (int) $user['id'];

/*
|--------------------------------------------------------------------------
| Inactive Account
|--------------------------------------------------------------------------
*/

if (($user['status'] ?? '') !== 'active') {
    erp_login_safe_audit(
        $conn,
        $userId,
        'Failed login: account inactive'
    );

    jsonResponse([
        'status'  => 403,
        'success' => false,
        'message' => 'ইউজার একাউন্ট সক্রিয় নয়',
        'data'    => null,
    ], 403);
}

/*
|--------------------------------------------------------------------------
| Account Lock পরীক্ষা
|--------------------------------------------------------------------------
*/

if (!empty($user['locked_until'])) {
    $lockedUntilTimestamp = strtotime(
        (string) $user['locked_until']
    );

    if (
        $lockedUntilTimestamp !== false
        && $lockedUntilTimestamp > time()
    ) {
        $remainingMinutes = (int) ceil(
            ($lockedUntilTimestamp - time()) / 60
        );

        erp_login_safe_audit(
            $conn,
            $userId,
            'Failed login: account currently locked'
        );

        jsonResponse([
            'status'  => 423,
            'success' => false,
            'message' => "অ্যাকাউন্ট সাময়িকভাবে লক করা হয়েছে। {$remainingMinutes} মিনিট পর আবার চেষ্টা করুন।",
            'data'    => null,
        ], 423);
    }

    /*
     * Lock সময় শেষ হলে attempts reset করা হবে।
     */
    $resetLock = $conn->prepare(
        "
        UPDATE users
        SET
            failed_login_attempts = 0,
            locked_until = NULL
        WHERE id = ?
        "
    );

    if ($resetLock) {
        $resetLock->bind_param('i', $userId);
        $resetLock->execute();
        $resetLock->close();
    }

    $user['failed_login_attempts'] = 0;
    $user['locked_until'] = null;
}

/*
|--------------------------------------------------------------------------
| Password Verification
|--------------------------------------------------------------------------
*/

$storedPassword = (string) ($user['password'] ?? '');
$passwordInfo = password_get_info($storedPassword);

$isPasswordValid = false;
$isLegacyPlainPassword = false;

if (!empty($passwordInfo['algo'])) {
    $isPasswordValid = password_verify(
        $password,
        $storedPassword
    );
} else {
    /*
     * পুরোনো plain-text password compatibility।
     * সফল হলে নিচে স্বয়ংক্রিয়ভাবে hash হবে।
     */
    $isPasswordValid = hash_equals(
        $storedPassword,
        $password
    );

    $isLegacyPlainPassword = $isPasswordValid;
}

/*
|--------------------------------------------------------------------------
| ভুল Password
|--------------------------------------------------------------------------
*/

if (!$isPasswordValid) {
    $previousFailedAttempts = (int) (
        $user['failed_login_attempts'] ?? 0
    );

    $newFailedAttempts = $previousFailedAttempts + 1;
    $lockedUntil = null;

    if (
        $newFailedAttempts
        >= ERP_LOGIN_MAX_FAILED_ATTEMPTS
    ) {
        $lockedUntil = date(
            'Y-m-d H:i:s',
            time() + (
                ERP_LOGIN_LOCKOUT_MINUTES * 60
            )
        );
    }

    $updateFailed = $conn->prepare(
        "
        UPDATE users
        SET
            failed_login_attempts = ?,
            locked_until = ?
        WHERE id = ?
        "
    );

    if ($updateFailed) {
        $updateFailed->bind_param(
            'isi',
            $newFailedAttempts,
            $lockedUntil,
            $userId
        );

        $updateFailed->execute();
        $updateFailed->close();
    }

    if (
        $newFailedAttempts
        >= ERP_LOGIN_MAX_FAILED_ATTEMPTS
    ) {
        erp_login_safe_audit(
            $conn,
            $userId,
            'Account locked after repeated failed login attempts'
        );

        jsonResponse([
            'status'  => 423,
            'success' => false,
            'message' => 'অনেকবার ভুল হয়েছে। অ্যাকাউন্ট ১৫ মিনিটের জন্য লক করা হয়েছে।',
            'data'    => null,
        ], 423);
    }

    erp_login_safe_audit(
        $conn,
        $userId,
        'Failed login: incorrect password'
    );

    jsonResponse([
        'status'  => 401,
        'success' => false,
        'message' => 'ইমেইল বা পাসওয়ার্ড ভুল!',
        'data'    => null,
    ], 401);
}

/*
|--------------------------------------------------------------------------
| পুরোনো Plain Password স্বয়ংক্রিয়ভাবে Hash করা
|--------------------------------------------------------------------------
*/

if ($isLegacyPlainPassword) {
    $newPasswordHash = password_hash(
        $password,
        PASSWORD_BCRYPT,
        ['cost' => 12]
    );

    if ($newPasswordHash !== false) {
        $upgradePassword = $conn->prepare(
            "
            UPDATE users
            SET
                password = ?,
                password_changed_at = NOW()
            WHERE id = ?
            "
        );

        if ($upgradePassword) {
            $upgradePassword->bind_param(
                'si',
                $newPasswordHash,
                $userId
            );

            $upgradePassword->execute();
            $upgradePassword->close();
        }
    }
}

/*
|--------------------------------------------------------------------------
| Login সফল
|--------------------------------------------------------------------------
*/

session_regenerate_id(true);

$clientIp = erp_login_client_ip();
$userAgentHash = erp_login_user_agent_hash();

$_SESSION['user_id'] = $userId;
$_SESSION['user_name'] = (string) $user['name'];
$_SESSION['user_role'] = (string) $user['role'];
$_SESSION['role'] = (string) $user['role'];

$_SESSION['LOGIN_TIME'] = time();
$_SESSION['LAST_ACTIVITY'] = time();
$_SESSION['LAST_REGEN'] = time();
$_SESSION['BIND_IP'] = $clientIp;
$_SESSION['BIND_UA'] = $userAgentHash;

/*
|--------------------------------------------------------------------------
| Login সফল হলে CSRF Token পরিবর্তন
|--------------------------------------------------------------------------
*/

if (function_exists('csrf_rotate_token')) {
    $csrfToken = csrf_rotate_token();
} else {
    $csrfToken = bin2hex(random_bytes(32));
    $_SESSION['csrf_token'] = $csrfToken;
}

/*
|--------------------------------------------------------------------------
| Login Information Update
|--------------------------------------------------------------------------
|
| এখানে last_login_at = NOW() যোগ করা হয়েছে।
|--------------------------------------------------------------------------
*/

$updateLogin = $conn->prepare(
    "
    UPDATE users
    SET
        failed_login_attempts = 0,
        locked_until = NULL,
        last_login_ip = ?,
        last_login_ua_hash = ?,
        last_login_at = NOW()
    WHERE id = ?
    "
);

if ($updateLogin) {
    $updateLogin->bind_param(
        'ssi',
        $clientIp,
        $userAgentHash,
        $userId
    );

    $updateLogin->execute();
    $updateLogin->close();
}

/*
|--------------------------------------------------------------------------
| সফল Login Audit
|--------------------------------------------------------------------------
*/

erp_login_safe_audit(
    $conn,
    $userId,
    'User login successful — TEST environment'
);

/*
|--------------------------------------------------------------------------
| নতুন CSRF Token Browser-এ পাঠানো
|--------------------------------------------------------------------------
*/

header('X-CSRF-Token: ' . $csrfToken);

jsonResponse([
    'status'  => 200,
    'success' => true,
    'message' => 'লগইন সফল',
    'data'    => [
        'user_id'    => $userId,
        'name'       => (string) $user['name'],
        'role'       => (string) $user['role'],
        'csrf_token' => $csrfToken,
    ],
], 200);