<?php

session_start();

require_once __DIR__ . '/config/database.php';


/*
|--------------------------------------------------------------------------
| Disable Browser Caching
|--------------------------------------------------------------------------
*/

header(
    "Cache-Control: no-store, no-cache, must-revalidate, max-age=0"
);

header("Pragma: no-cache");
header("Expires: 0");


/*
|--------------------------------------------------------------------------
| CSRF Token
|--------------------------------------------------------------------------
*/

if (empty($_SESSION['reset_password_csrf'])) {

    $_SESSION['reset_password_csrf'] =
        bin2hex(
            random_bytes(32)
        );

}


/*
|--------------------------------------------------------------------------
| Old Form Values
|--------------------------------------------------------------------------
*/

$oldPhone =
    $_SESSION['reset_old_phone'] ?? '';

unset(
    $_SESSION['reset_old_phone']
);


/*
|--------------------------------------------------------------------------
| Handle Password Reset
|--------------------------------------------------------------------------
*/

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


    /*
    |--------------------------------------------------------------------------
    | Receive Data
    |--------------------------------------------------------------------------
    */

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


    $resetCode =
        strtoupper(
            trim(
                $_POST['reset_code'] ?? ''
            )
        );


    /*
     * Remove accidental spaces.
     *
     * Example:
     * CB- 482913
     * becomes:
     * CB-482913
     */

    $resetCode =
        preg_replace(
            '/\s+/',
            '',
            $resetCode
        );


    $newPassword =
        $_POST['new_password'] ?? '';


    $confirmPassword =
        $_POST['confirm_password'] ?? '';


    $csrfToken =
        $_POST['csrf_token'] ?? '';


    $_SESSION['reset_old_phone'] =
        $phone;


    /*
    |--------------------------------------------------------------------------
    | CSRF Validation
    |--------------------------------------------------------------------------
    */

    if (
        !hash_equals(
            $_SESSION['reset_password_csrf'],
            $csrfToken
        )
    ) {

        $_SESSION['reset_password_error'] =
            "Your session has expired. Please try again.";

        header(
            "Location: reset-password.php"
        );

        exit();

    }


    /*
    |--------------------------------------------------------------------------
    | Basic Validation
    |--------------------------------------------------------------------------
    */

    if (
        $phone === '' ||
        $resetCode === '' ||
        $newPassword === '' ||
        $confirmPassword === ''
    ) {

        $_SESSION['reset_password_error'] =
            "Please complete all required fields.";

        header(
            "Location: reset-password.php"
        );

        exit();

    }


    /*
    |--------------------------------------------------------------------------
    | Password Length
    |--------------------------------------------------------------------------
    */

    if (
        strlen($newPassword) < 8
    ) {

        $_SESSION['reset_password_error'] =
            "Your new password must contain at least 8 characters.";

        header(
            "Location: reset-password.php"
        );

        exit();

    }


    /*
    |--------------------------------------------------------------------------
    | Password Confirmation
    |--------------------------------------------------------------------------
    */

    if (
        $newPassword !==
        $confirmPassword
    ) {

        $_SESSION['reset_password_error'] =
            "The two passwords do not match.";

        header(
            "Location: reset-password.php"
        );

        exit();

    }


    try {


        /*
        |--------------------------------------------------------------------------
        | Begin Secure Transaction
        |--------------------------------------------------------------------------
        */

        $pdo->beginTransaction();


        /*
        |--------------------------------------------------------------------------
        | Get Latest Approved Request
        |--------------------------------------------------------------------------
        |
        | FOR UPDATE prevents two reset attempts from
        | successfully using the same code at the same time.
        |
        */

        $stmt = $pdo->prepare("
            SELECT

                prr.id,
                prr.user_id,
                prr.phone,
                prr.token_hash,
                prr.token_expires_at,
                prr.attempt_count,
                prr.status,

                u.fullname,
                u.status AS user_status

            FROM password_reset_requests prr

            INNER JOIN users u
                ON u.id = prr.user_id

            WHERE
                prr.phone = ?
                AND prr.status = 'approved'

            ORDER BY prr.id DESC

            LIMIT 1

            FOR UPDATE
        ");


        $stmt->execute([
            $phone
        ]);


        $resetRequest =
            $stmt->fetch(
                PDO::FETCH_ASSOC
            );


        /*
        |--------------------------------------------------------------------------
        | No Approved Request
        |--------------------------------------------------------------------------
        */

        if (!$resetRequest) {

            $pdo->rollBack();


            $_SESSION['reset_password_error'] =
                "The reset information is invalid or the request is no longer active.";


            header(
                "Location: reset-password.php"
            );

            exit();

        }


        /*
        |--------------------------------------------------------------------------
        | Check User Account Status
        |--------------------------------------------------------------------------
        */

        if (
            $resetRequest['user_status']
            === 'suspended'
        ) {

            $pdo->rollBack();


            $_SESSION['reset_password_error'] =
                "This account is currently suspended. Please contact Complete Bliss support.";


            header(
                "Location: reset-password.php"
            );

            exit();

        }


        /*
        |--------------------------------------------------------------------------
        | Check Expiry
        |--------------------------------------------------------------------------
        */

/*
|--------------------------------------------------------------------------
| Check Expiry Using MySQL Time
|--------------------------------------------------------------------------
|
| We use MySQL's NOW() instead of PHP time() so both the
| generated expiry time and the expiry check use the same clock.
|
*/

$expiryCheck =
    $pdo->prepare("
        SELECT
            CASE
                WHEN token_expires_at IS NULL
                    OR token_expires_at < NOW()
                THEN 1
                ELSE 0
            END AS is_expired

        FROM password_reset_requests

        WHERE id = ?

        LIMIT 1
    ");


$expiryCheck->execute([
    $resetRequest['id']
]);


$isExpired =
    (int)$expiryCheck->fetchColumn();


if ($isExpired === 1) {


    $expireStmt =
        $pdo->prepare("
            UPDATE password_reset_requests

            SET
                status = 'expired',
                token_hash = NULL,
                token_expires_at = NULL

            WHERE id = ?
        ");


    $expireStmt->execute([
        $resetRequest['id']
    ]);


    $pdo->commit();


    $_SESSION['reset_password_error'] =
        "This password reset code has expired. Please submit a new recovery request.";


    header(
        "Location: reset-password.php"
    );

    exit();

}


        /*
        |--------------------------------------------------------------------------
        | Check Attempt Limit
        |--------------------------------------------------------------------------
        */

        if (
            (int)$resetRequest[
                'attempt_count'
            ] >= 5
        ) {


            $expireStmt =
                $pdo->prepare("
                    UPDATE password_reset_requests

                    SET
                        status = 'expired',
                        token_hash = NULL,
                        token_expires_at = NULL

                    WHERE id = ?
                ");


            $expireStmt->execute([
                $resetRequest['id']
            ]);


            $pdo->commit();


            $_SESSION['reset_password_error'] =
                "Too many incorrect attempts. Please request a new password reset code.";


            header(
                "Location: reset-password.php"
            );

            exit();

        }


        /*
        |--------------------------------------------------------------------------
        | Verify Reset Code
        |--------------------------------------------------------------------------
        */

        $codeIsValid =
            !empty(
                $resetRequest['token_hash']
            )
            &&
            password_verify(
                $resetCode,
                $resetRequest['token_hash']
            );


        /*
        |--------------------------------------------------------------------------
        | Wrong Reset Code
        |--------------------------------------------------------------------------
        */

        if (!$codeIsValid) {


            $newAttemptCount =
                (int)$resetRequest[
                    'attempt_count'
                ] + 1;


            /*
            |--------------------------------------------------------------------------
            | Fifth Wrong Attempt
            |--------------------------------------------------------------------------
            */

            if ($newAttemptCount >= 5) {


                $attemptStmt =
                    $pdo->prepare("
                        UPDATE password_reset_requests

                        SET
                            attempt_count = ?,
                            status = 'expired',
                            token_hash = NULL,
                            token_expires_at = NULL

                        WHERE id = ?
                    ");


                $attemptStmt->execute([

                    $newAttemptCount,

                    $resetRequest['id']

                ]);


                $pdo->commit();


                $_SESSION['reset_password_error'] =
                    "Too many incorrect attempts. This reset code has been cancelled. Please request a new one.";


                header(
                    "Location: reset-password.php"
                );

                exit();

            }


            /*
            |--------------------------------------------------------------------------
            | Wrong Attempt Under Limit
            |--------------------------------------------------------------------------
            */

            $attemptStmt =
                $pdo->prepare("
                    UPDATE password_reset_requests

                    SET attempt_count = ?

                    WHERE id = ?
                ");


            $attemptStmt->execute([

                $newAttemptCount,

                $resetRequest['id']

            ]);


            $pdo->commit();


            $remainingAttempts =
                5 - $newAttemptCount;


            $_SESSION['reset_password_error'] =
                "The reset code is incorrect. "
                .
                $remainingAttempts
                .
                " attempt"
                .
                (
                    $remainingAttempts === 1
                    ? ""
                    : "s"
                )
                .
                " remaining.";


            header(
                "Location: reset-password.php"
            );

            exit();

        }


        /*
        |--------------------------------------------------------------------------
        | Hash New Password
        |--------------------------------------------------------------------------
        */

        $newPasswordHash =
            password_hash(
                $newPassword,
                PASSWORD_DEFAULT
            );


        /*
        |--------------------------------------------------------------------------
        | Update Member Password
        |--------------------------------------------------------------------------
        */

        $updatePassword =
            $pdo->prepare("
                UPDATE users

                SET password = ?

                WHERE id = ?
            ");


        $updatePassword->execute([

            $newPasswordHash,

            $resetRequest['user_id']

        ]);


        /*
        |--------------------------------------------------------------------------
        | Mark Current Request Completed
        |--------------------------------------------------------------------------
        |
        | Token is removed so the same code can
        | never be used again.
        |
        */

        $completeRequest =
            $pdo->prepare("
                UPDATE password_reset_requests

                SET
                    status = 'completed',
                    token_hash = NULL,
                    token_expires_at = NULL,
                    completed_at = NOW()

                WHERE id = ?
            ");


        $completeRequest->execute([
            $resetRequest['id']
        ]);


        /*
        |--------------------------------------------------------------------------
        | Cancel Other Active Reset Requests
        |--------------------------------------------------------------------------
        |
        | If the member had another recovery request,
        | invalidate it after the password is changed.
        |
        */

        $cancelOtherRequests =
            $pdo->prepare("
                UPDATE password_reset_requests

                SET
                    status = 'expired',
                    token_hash = NULL,
                    token_expires_at = NULL

                WHERE
                    user_id = ?
                    AND id != ?
                    AND status IN (
                        'pending',
                        'approved',
                        'email_sent'
                    )
            ");


        $cancelOtherRequests->execute([

            $resetRequest['user_id'],

            $resetRequest['id']

        ]);


        /*
        |--------------------------------------------------------------------------
        | Commit Everything
        |--------------------------------------------------------------------------
        */

        $pdo->commit();


        /*
        |--------------------------------------------------------------------------
        | New CSRF Token
        |--------------------------------------------------------------------------
        */

        unset(
            $_SESSION[
                'reset_password_csrf'
            ]
        );


        unset(
            $_SESSION[
                'reset_old_phone'
            ]
        );


        /*
        |--------------------------------------------------------------------------
        | Login Success Message
        |--------------------------------------------------------------------------
        */

        $_SESSION['success'] =
            "Your password has been changed successfully. You can now log in with your new password.";


        header(
            "Location: login.php"
        );

        exit();


    } catch (Exception $e) {


        /*
        |--------------------------------------------------------------------------
        | Rollback If Something Fails
        |--------------------------------------------------------------------------
        */

        if ($pdo->inTransaction()) {

            $pdo->rollBack();

        }


        $_SESSION['reset_password_error'] =
            "Unable to reset your password right now. Please try again.";


        header(
            "Location: reset-password.php"
        );

        exit();

    }

}


/*
|--------------------------------------------------------------------------
| Error Message
|--------------------------------------------------------------------------
*/

$resetPasswordError =
    $_SESSION[
        'reset_password_error'
    ] ?? null;


unset(
    $_SESSION[
        'reset_password_error'
    ]
);

?>

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">


    <meta
        name="viewport"
        content="width=device-width, initial-scale=1.0"
    >


    <title>
        Reset Password | Complete Bliss Solutions
    </title>


    <!-- FONTS -->

    <link
        href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@600;700;800&display=swap"
        rel="stylesheet"
    >


    <!-- FONT AWESOME -->

    <link
        rel="stylesheet"
        href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
    >


    <!-- SAME AUTH CSS AS LOGIN -->

    <link
        rel="stylesheet"
        href="assets/css/login.css?v=<?= filemtime(__DIR__ . '/assets/css/login.css') ?>"
    >

</head>


<body>


<div class="cbx-login-page">


    <!-- =====================================================
         LEFT SIDE
    ====================================================== -->

    <section class="cbx-login-visual">


        <div class="cbx-login-bg">

            <img
                src="public-site/assets/images/how-it-works.png"
                alt=""
            >

        </div>


        <div class="cbx-login-overlay"></div>



        <div class="cbx-login-brand">

            <a href="index.php">

                <img
                    src="public-site/assets/images/logo.png"
                    alt="Complete Bliss Solutions"
                >

            </a>

        </div>



        <div class="cbx-login-visual-content">


            <div class="cbx-login-visual-badge">

                <i class="fa-solid fa-lock"></i>

                <span>
                    SECURE PASSWORD RESET
                </span>

            </div>


            <h1>

                Create your

                <span>
                    new password.
                </span>

            </h1>


            <p>
                Enter the one-time recovery code provided
                after your account recovery request was
                approved.
            </p>



            <div class="cbx-forgot-trust">


                <div>

                    <i class="fa-solid fa-clock"></i>

                    <span>

                        <strong>
                            30-Minute Code
                        </strong>

                        <small>
                            Your reset code automatically expires
                            after 30 minutes.
                        </small>

                    </span>

                </div>


                <div>

                    <i class="fa-solid fa-shield-halved"></i>

                    <span>

                        <strong>
                            One-Time Use
                        </strong>

                        <small>
                            Once your password is changed, the
                            recovery code becomes permanently invalid.
                        </small>

                    </span>

                </div>


            </div>


        </div>



        <div class="cbx-login-visual-bottom">

            <span>

                <i class="fa-solid fa-lock"></i>

                Secure Complete Bliss account recovery

            </span>

        </div>


    </section>



    <!-- =====================================================
         RIGHT SIDE
    ====================================================== -->

    <section class="cbx-login-form-side">


        <div class="cbx-login-mobile-header">


            <a href="index.php">

                <img
                    src="public-site/assets/images/logo.png"
                    alt="Complete Bliss Solutions"
                >

            </a>


            <a
                href="login.php"
                class="cbx-login-home-mobile"
            >

                <i class="fa-solid fa-arrow-left"></i>

                Login

            </a>


        </div>



        <div class="cbx-login-form-wrap">


            <a
                href="forgot-password.php"
                class="cbx-login-back"
            >

                <i class="fa-solid fa-arrow-left"></i>

                Back to Recovery

            </a>



            <div class="cbx-login-heading">


                <div class="cbx-login-icon">

                    <i class="fa-solid fa-lock-open"></i>

                </div>


                <span>
                    PASSWORD RESET
                </span>


                <h2>
                    Set a new password
                </h2>


                <p>
                    Enter your registered phone number,
                    one-time reset code and your new password.
                </p>


            </div>



            <!-- =================================================
                 FORM
            ================================================== -->

            <form
                action=""
                method="POST"
                class="cbx-login-form"
                autocomplete="off"
            >


                <!-- CSRF -->

                <input
                    type="hidden"
                    name="csrf_token"
                    value="<?= htmlspecialchars(
                        $_SESSION['reset_password_csrf']
                    ); ?>"
                >



                <!-- PHONE -->

                <div class="cbx-form-group">


                    <label for="phone">

                        Registered Phone Number

                    </label>


                    <div class="cbx-input-wrap">


                        <div class="cbx-input-icon">

                            <i class="fa-solid fa-phone"></i>

                        </div>


                        <input
                            type="tel"
                            id="phone"
                            name="phone"
                            placeholder="Enter your registered phone number"
                            value="<?= htmlspecialchars(
                                $oldPhone
                            ); ?>"
                            autocomplete="tel"
                            required
                        >


                    </div>


                </div>



                <!-- RESET CODE -->

                <div class="cbx-form-group">


                    <label for="reset_code">

                        One-Time Reset Code

                    </label>


                    <div class="cbx-input-wrap">


                        <div class="cbx-input-icon">

                            <i class="fa-solid fa-key"></i>

                        </div>


                        <input
                            type="text"
                            id="reset_code"
                            name="reset_code"
                            placeholder="e.g. CB-482913"
                            maxlength="20"
                            autocomplete="one-time-code"
                            required
                        >


                    </div>


                </div>



                <!-- NEW PASSWORD -->

                <div class="cbx-form-group">


                    <label for="new_password">

                        New Password

                    </label>


                    <div class="cbx-input-wrap">


                        <div class="cbx-input-icon">

                            <i class="fa-solid fa-lock"></i>

                        </div>


                        <input
                            type="password"
                            id="new_password"
                            name="new_password"
                            placeholder="Minimum 8 characters"
                            minlength="8"
                            autocomplete="new-password"
                            required
                        >


                    </div>


                </div>



                <!-- CONFIRM PASSWORD -->

                <div class="cbx-form-group">


                    <label for="confirm_password">

                        Confirm New Password

                    </label>


                    <div class="cbx-input-wrap">


                        <div class="cbx-input-icon">

                            <i class="fa-solid fa-lock"></i>

                        </div>


                        <input
                            type="password"
                            id="confirm_password"
                            name="confirm_password"
                            placeholder="Enter the new password again"
                            minlength="8"
                            autocomplete="new-password"
                            required
                        >


                    </div>


                </div>



                <!-- SECURITY INFORMATION -->

                <div class="cbx-forgot-info">


                    <div>

                        <i class="fa-solid fa-shield-halved"></i>

                    </div>


                    <p>
                        Your recovery code can only be used once.
                        After five incorrect attempts, the request
                        will automatically expire and you will need
                        to request a new code.
                    </p>


                </div>



                <!-- SUBMIT -->

                <button
                    type="submit"
                    class="cbx-login-btn"
                >

                    <span>
                        Change Password
                    </span>

                    <i class="fa-solid fa-arrow-right"></i>

                </button>



                <!-- BACK TO LOGIN -->

                <div class="cbx-login-register">


                    <span>
                        Remember your password?
                    </span>


                    <a href="login.php">

                        Back to Login

                        <i class="fa-solid fa-arrow-right"></i>

                    </a>


                </div>


            </form>



            <div class="cbx-login-form-footer">


                <i class="fa-solid fa-shield-halved"></i>

                <span>
                    Secure password reset
                </span>


                <span class="cbx-login-dot"></span>


                <a href="index.php#contact">

                    Need help?

                </a>


            </div>


        </div>


    </section>


</div>



<script
    src="https://cdn.jsdelivr.net/npm/sweetalert2@11"
></script>



<?php if ($resetPasswordError): ?>

<script>

document.addEventListener(
    "DOMContentLoaded",
    function () {

        Swal.fire({

            icon:
                "error",

            title:
                "Unable to Reset Password",

            text:
                <?= json_encode(
                    $resetPasswordError
                ); ?>,

            confirmButtonColor:
                "#2563eb"

        });

    }
);

</script>

<?php endif; ?>



</body>

</html>