<?php

require_once __DIR__ . '/db.php';
require_once __DIR__ . '/customers.php';

/**
 * Return the portal account connected to a Customer History key.
 *
 * Merged customer keys are resolved first so the account stays connected
 * to the combined customer history.
 */
function sparrow_get_portal_account_by_customer_key(string $customer_key): ?array
{
    $customer_key = sparrow_resolve_customer_key(trim($customer_key));

    if ($customer_key === '') {
        return null;
    }

    $stmt = sparrow_db()->prepare("
        SELECT
            id,
            customer_key,
            username,
            email,
			            billing_name,
            billing_address_1,
            billing_address_2,
            billing_city,
            billing_state,
            billing_postal_code,
            shipping_name,
            shipping_address_1,
            shipping_address_2,
            shipping_city,
            shipping_state,
            shipping_postal_code,
            is_active,
            must_change_password,
            last_login_at,
            created_at,
            updated_at
        FROM customer_portal_accounts
        WHERE customer_key = :customer_key
        LIMIT 1
    ");

    $stmt->execute([
        ':customer_key' => $customer_key,
    ]);

    $account = $stmt->fetch();

    return $account ?: null;
}

/**
 * Return a portal account by username, including its password hash for login.
 */
function sparrow_get_portal_account_by_username(string $username): ?array
{
    $username = trim($username);

    if ($username === '') {
        return null;
    }

    $stmt = sparrow_db()->prepare("
        SELECT
            id,
            customer_key,
            username,
            email,
			billing_name,
billing_address_1,
billing_address_2,
billing_city,
billing_state,
billing_postal_code,
shipping_name,
shipping_address_1,
shipping_address_2,
shipping_city,
shipping_state,
shipping_postal_code,
            password_hash,
            is_active,
            must_change_password,
            last_login_at,
            created_at,
            updated_at
        FROM customer_portal_accounts
        WHERE username = :username
        LIMIT 1
    ");

    $stmt->execute([
        ':username' => $username,
    ]);

    $account = $stmt->fetch();

    return $account ?: null;
}

/**
 * Return one portal account by its session ID.
 */
function sparrow_get_portal_account_by_id(int $account_id): ?array
{
    if ($account_id <= 0) {
        return null;
    }

    $stmt = sparrow_db()->prepare("
        SELECT
            id,
            customer_key,
            username,
            email,
			billing_name,
billing_address_1,
billing_address_2,
billing_city,
billing_state,
billing_postal_code,
shipping_name,
shipping_address_1,
shipping_address_2,
shipping_city,
shipping_state,
shipping_postal_code,
            is_active,
            must_change_password,
            last_login_at,
            created_at,
            updated_at
        FROM customer_portal_accounts
        WHERE id = :id
        LIMIT 1
    ");

    $stmt->execute([
        ':id' => $account_id,
    ]);

    $account = $stmt->fetch();

    return $account ?: null;
}

/**
 * Create one portal account for a Customer History record.
 */
function sparrow_create_portal_account(
    string $customer_key,
    string $username,
    string $password,
    string $email = ''
): int {
    $customer_key = sparrow_resolve_customer_key(trim($customer_key));
    $username = trim($username);
    $email = trim($email);

    if ($customer_key === '') {
        throw new InvalidArgumentException('A customer is required.');
    }

    if ($username === '') {
        throw new InvalidArgumentException('Please enter a username.');
    }

    if (strlen($username) > 100) {
        throw new InvalidArgumentException('The username must be 100 characters or fewer.');
    }

    if (!preg_match('/^[A-Za-z0-9._-]+$/', $username)) {
        throw new InvalidArgumentException(
            'The username may contain letters, numbers, periods, underscores, and hyphens.'
        );
    }

    if (strlen($password) < 8) {
        throw new InvalidArgumentException('The temporary password must be at least 8 characters.');
    }

    if (strlen($password) > 200) {
        throw new InvalidArgumentException('The password is too long.');
    }

    if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException('Please enter a valid portal email or leave it blank.');
    }

    if (strlen($email) > 190) {
        throw new InvalidArgumentException('The portal email must be 190 characters or fewer.');
    }

    if (sparrow_get_portal_account_by_customer_key($customer_key)) {
        throw new RuntimeException('This customer already has a portal account.');
    }

    if (sparrow_get_portal_account_by_username($username)) {
        throw new RuntimeException('That username is already in use.');
    }

    $stmt = sparrow_db()->prepare("
        INSERT INTO customer_portal_accounts (
            customer_key,
            username,
            email,
			billing_name,
billing_address_1,
billing_address_2,
billing_city,
billing_state,
billing_postal_code,
shipping_name,
shipping_address_1,
shipping_address_2,
shipping_city,
shipping_state,
shipping_postal_code,
            password_hash,
            is_active,
            must_change_password
        ) VALUES (
            :customer_key,
            :username,
            :email,
            :password_hash,
            1,
            1
        )
    ");

    $stmt->execute([
        ':customer_key' => $customer_key,
        ':username' => $username,
        ':email' => $email !== '' ? $email : null,
        ':password_hash' => password_hash($password, PASSWORD_DEFAULT),
    ]);

    return (int) sparrow_db()->lastInsertId();
}

/**
 * Replace a customer's temporary password.
 */
function sparrow_reset_portal_password(int $account_id, string $password): void
{
    if ($account_id <= 0) {
        throw new InvalidArgumentException('A portal account is required.');
    }

    if (strlen($password) < 8) {
        throw new InvalidArgumentException('The temporary password must be at least 8 characters.');
    }

    if (strlen($password) > 200) {
        throw new InvalidArgumentException('The password is too long.');
    }

    $stmt = sparrow_db()->prepare("
        UPDATE customer_portal_accounts
        SET
            password_hash = :password_hash,
            must_change_password = 1
        WHERE id = :id
        LIMIT 1
    ");

    $stmt->execute([
        ':password_hash' => password_hash($password, PASSWORD_DEFAULT),
        ':id' => $account_id,
    ]);
}

/**
 * Activate or pause portal access without deleting the account.
 */
function sparrow_set_portal_account_active(int $account_id, bool $is_active): void
{
    if ($account_id <= 0) {
        throw new InvalidArgumentException('A portal account is required.');
    }

    $stmt = sparrow_db()->prepare("
        UPDATE customer_portal_accounts
        SET is_active = :is_active
        WHERE id = :id
        LIMIT 1
    ");

    $stmt->execute([
        ':is_active' => $is_active ? 1 : 0,
        ':id' => $account_id,
    ]);
}

/**
 * Save or remove the real email used for future portal notifications.
 */
function sparrow_update_portal_email(int $account_id, string $email): void
{
    $email = trim($email);

    if ($account_id <= 0) {
        throw new InvalidArgumentException('A portal account is required.');
    }

    if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException('Please enter a valid portal email or leave it blank.');
    }

    if (strlen($email) > 190) {
        throw new InvalidArgumentException('The portal email must be 190 characters or fewer.');
    }

    $stmt = sparrow_db()->prepare("
        UPDATE customer_portal_accounts
        SET email = :email
        WHERE id = :id
        LIMIT 1
    ");

    $stmt->execute([
        ':email' => $email !== '' ? $email : null,
        ':id' => $account_id,
    ]);
}

/**
 * Save billing and shipping addresses for one portal account.
 */
function sparrow_update_portal_addresses(
    int $account_id,
    array $address_data
): void {
    if ($account_id <= 0) {
        throw new InvalidArgumentException(
            'A portal account is required.'
        );
    }

    $fields = [
        'billing_name' => 150,
        'billing_address_1' => 190,
        'billing_address_2' => 190,
        'billing_city' => 100,
        'billing_state' => 100,
        'billing_postal_code' => 20,
        'shipping_name' => 150,
        'shipping_address_1' => 190,
        'shipping_address_2' => 190,
        'shipping_city' => 100,
        'shipping_state' => 100,
        'shipping_postal_code' => 20,
    ];

    $cleaned_addresses = [];

    foreach ($fields as $field_name => $maximum_length) {
        $field_value = trim(
            (string) ($address_data[$field_name] ?? '')
        );

        if (strlen($field_value) > $maximum_length) {
            throw new InvalidArgumentException(
                'One or more address fields are too long.'
            );
        }

        $cleaned_addresses[$field_name] =
            $field_value !== ''
                ? $field_value
                : null;
    }

    $stmt = sparrow_db()->prepare("
        UPDATE customer_portal_accounts
        SET
            billing_name = :billing_name,
            billing_address_1 = :billing_address_1,
            billing_address_2 = :billing_address_2,
            billing_city = :billing_city,
            billing_state = :billing_state,
            billing_postal_code = :billing_postal_code,
            shipping_name = :shipping_name,
            shipping_address_1 = :shipping_address_1,
            shipping_address_2 = :shipping_address_2,
            shipping_city = :shipping_city,
            shipping_state = :shipping_state,
            shipping_postal_code = :shipping_postal_code
        WHERE id = :account_id
        LIMIT 1
    ");

    $stmt->execute([
        ':billing_name' =>
            $cleaned_addresses['billing_name'],
        ':billing_address_1' =>
            $cleaned_addresses['billing_address_1'],
        ':billing_address_2' =>
            $cleaned_addresses['billing_address_2'],
        ':billing_city' =>
            $cleaned_addresses['billing_city'],
        ':billing_state' =>
            $cleaned_addresses['billing_state'],
        ':billing_postal_code' =>
            $cleaned_addresses['billing_postal_code'],
        ':shipping_name' =>
            $cleaned_addresses['shipping_name'],
        ':shipping_address_1' =>
            $cleaned_addresses['shipping_address_1'],
        ':shipping_address_2' =>
            $cleaned_addresses['shipping_address_2'],
        ':shipping_city' =>
            $cleaned_addresses['shipping_city'],
        ':shipping_state' =>
            $cleaned_addresses['shipping_state'],
        ':shipping_postal_code' =>
            $cleaned_addresses['shipping_postal_code'],
        ':account_id' => $account_id,
    ]);
}

/**
 * Change the password for one portal account.
 */
function sparrow_change_portal_password(
    int $account_id,
    string $current_password,
    string $new_password
): void {
    if ($account_id <= 0) {
        throw new InvalidArgumentException(
            'A portal account is required.'
        );
    }

    if ($current_password === '') {
        throw new InvalidArgumentException(
            'Please enter your current password.'
        );
    }

    if (strlen($new_password) < 8) {
        throw new InvalidArgumentException(
            'Your new password must be at least 8 characters.'
        );
    }

    if (strlen($new_password) > 72) {
        throw new InvalidArgumentException(
            'Your new password cannot be longer than 72 characters.'
        );
    }

    $stmt = sparrow_db()->prepare("
        SELECT password_hash
        FROM customer_portal_accounts
        WHERE id = :account_id
        LIMIT 1
    ");

    $stmt->execute([
        ':account_id' => $account_id,
    ]);

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

    if (!$account) {
        throw new InvalidArgumentException(
            'Your portal account could not be found.'
        );
    }

    $saved_password_hash = (string) (
        $account['password_hash'] ?? ''
    );

    if (
        $saved_password_hash === ''
        || !password_verify(
            $current_password,
            $saved_password_hash
        )
    ) {
        throw new InvalidArgumentException(
            'Your current password is incorrect.'
        );
    }

    if (
        password_verify(
            $new_password,
            $saved_password_hash
        )
    ) {
        throw new InvalidArgumentException(
            'Your new password must be different from your current password.'
        );
    }

    $new_password_hash = password_hash(
        $new_password,
        PASSWORD_DEFAULT
    );

    if ($new_password_hash === false) {
        throw new RuntimeException(
            'Your new password could not be secured.'
        );
    }

    $update_stmt = sparrow_db()->prepare("
        UPDATE customer_portal_accounts
        SET password_hash = :password_hash
        WHERE id = :account_id
        LIMIT 1
    ");

    $update_stmt->execute([
        ':password_hash' => $new_password_hash,
        ':account_id' => $account_id,
    ]);
}