<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\Ajax\Service;

use CompareProduct;
use Context;
use Customer;
use Hook;
use Tools;

if (!defined('_PS_VERSION_')) {
    exit;
}

class CustomerService
{
    public function __construct(private readonly Context $context)
    {
    }

    /**
     * @param array<string, mixed> $responseData payload returned by userDataCommerce
     *
     * @return array{is_guest: bool, firstname?: string, lastname?: string, challenge_available?: bool}
     */
    public function loginOrCreateByEmail(string $email, array $responseData): array
    {
        $data = $this->extractData($responseData);
        $customer = new Customer();
        $customer->getByEmail($data['email'] ?? $email);

        if ((int) $customer->id > 0) {
            if ($customer->is_guest) {
                $customer->firstname = (string) ($data['name'] ?? '');
                $customer->lastname = (string) ($data['surname'] ?? '');
                $customer->update();
            } else {
                // Logging into a registered shop account requires the backend to confirm the shopper
                // owns the email (shopLoginAllowed === verified email); a missing flag is treated as
                // not allowed and falls back to a guest checkout instead. This is an anti-takeover
                // guard: without it, a shopper who only verifies their own phone number could gain
                // login access to whichever registered account matches a typed email, without ever
                // proving they control that email/account.
                if (true !== ($responseData['shopLoginAllowed'] ?? null)) {
                    // When the backend explicitly reports the email as unverified, offer the email-OTP
                    // challenge so the real owner can verify and log in instead of being stranded (a
                    // registered PS email cannot buy as a guest). A missing flag stays a plain guest.
                    return [
                        'is_guest' => true,
                        'firstname' => (string) ($data['name'] ?? ''),
                        'lastname' => (string) ($data['surname'] ?? ''),
                        'challenge_available' => false === ($responseData['shopLoginAllowed'] ?? null),
                    ];
                }
                Hook::exec('actionBeforeAuthentication');
                if (class_exists('CompareProduct') && !isset($this->context->cookie->id_compare)) {
                    $this->context->cookie->id_compare = CompareProduct::getIdCompareByIdCustomer((int) $customer->id);
                }
            }

            $this->context->cookie->id_customer = (int) $customer->id;
            $this->context->updateCustomer($customer);

            return $customer->is_guest
                ? ['is_guest' => true, 'firstname' => (string) $customer->firstname, 'lastname' => (string) $customer->lastname]
                : ['is_guest' => false];
        }

        $customer->email = $email;
        $customer->passwd = Tools::hash(Tools::passwdGen());
        $customer->is_guest = true;
        $customer->firstname = (string) ($data['name'] ?? '');
        $customer->lastname = (string) ($data['surname'] ?? '');
        $customer->add();
        $this->context->cookie->id_customer = (int) $customer->id;
        $this->context->updateCustomer($customer);

        return [
            'is_guest' => true,
            'firstname' => (string) $customer->firstname,
            'lastname' => (string) $customer->lastname,
        ];
    }

    /**
     * @param array<string, mixed> $responseData
     *
     * @return array<string, mixed>
     */
    private function extractData(array $responseData): array
    {
        if (isset($responseData['data']) && is_array($responseData['data'])) {
            return $responseData['data'];
        }
        if (isset($responseData['userData']) && is_array($responseData['userData'])) {
            return $responseData['userData'];
        }

        return [];
    }
}
