<?php

namespace Myvetshop\Module\Clinique\Crypto;

class Hashing extends \PrestaShop\PrestaShop\Core\Crypto\Hashing
{
    /**
     * should contain hashing methods
     *
     * @var array<string, array{option: array<mixed>, hash: callable, verify: callable}>
     */
    protected $myvetshopHashMethods = [];

    protected function initMyvetshopHashMethods(): void
    {
        $this->myvetshopHashMethods = [
            'bcrypt' => [
                'option' => [],
                'hash' => function ($passwd, $staticSalt, $option) {
                    return \password_hash($passwd, PASSWORD_BCRYPT);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    /*
                     * Prevent enumeration because nothing happens
                     * when there is no, or an invalid hash.
                     * Also, change the password to be sure it's not maching
                     * the new hash.
                     * The new hash is equal to 'test' in BCRYPT context.
                     */
                    if (empty($hash)) {
                        $hash = '$2y$10$azRqq.pN0OlWjeVfVMZXOOwqYAx1hMfme6ZnDV.27grGOEZvG.uAO';
                        $passwd = 'wrongPassword';
                    }

                    return \password_verify($passwd, $hash);
                },
            ],
            'md5' => [
                'option' => [],
                'hash' => function ($passwd, $staticSalt, $option) {
                    return \md5($staticSalt . $passwd);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return \md5($staticSalt . $passwd) === $hash;
                },
            ],
            'md5kalivet' => [
                'option' => [],
                'hash' => function ($passwd, $staticSalt, $option) {
                    return \md5('wduFrqKC3Av08cjpwxicXou2FNd85BQgXvnJQjV12hVKhALyImNtEbhw' . $passwd);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return \md5('wduFrqKC3Av08cjpwxicXou2FNd85BQgXvnJQjV12hVKhALyImNtEbhw' . $passwd) === $hash;
                },
            ],
        ];
    }

    public function isFirstHash($passwd, $hash, $staticSalt = _COOKIE_KEY_)
    {
        if (!\count($this->myvetshopHashMethods)) {
            $this->initMyvetshopHashMethods();
        }

        $closure = \reset($this->myvetshopHashMethods);
        \assert(false !== $closure);

        return $closure['verify']($passwd, $hash, $staticSalt);
    }

    /**
     * Iterate on hash_methods array and return true if it matches.
     *
     * @param string $passwd The password you want to check
     * @param string $hash The hash you want to check
     * @param string $staticSalt A static salt
     *
     * @return bool `true` is returned if the function find a match else false
     */
    public function checkHash($passwd, $hash, $staticSalt = _COOKIE_KEY_)
    {
        if (!\count($this->myvetshopHashMethods)) {
            $this->initMyvetshopHashMethods();
        }

        foreach ($this->myvetshopHashMethods as $closure) {
            if ($closure['verify']($passwd, $hash, $staticSalt)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Hash the `$plaintextPassword` string and return the result of the 1st hashing method
     * contained in PrestaShop\PrestaShop\Core\Crypto\Hashing::hash_methods.
     *
     * @param string $plaintextPassword The password you want to hash
     * @param string $staticSalt The static salt
     *
     * @return string
     */
    public function hash($plaintextPassword, $staticSalt = _COOKIE_KEY_)
    {
        if (!\count($this->myvetshopHashMethods)) {
            $this->initMyvetshopHashMethods();
        }

        $closure = \reset($this->myvetshopHashMethods);
        \assert(false !== $closure);

        return $closure['hash']($plaintextPassword, $staticSalt, $closure['option']);
    }
}
