<?php
/**
 * @package    Proxim
 * @author     Dominic Tanui <dominic@codeworldweb.com.dev | https://codeworldweb.com.dev>
 * @copyright  2019 Proxim
 * @version    1.5.0
 * @since      File available since Release 1.0.0
 */

namespace Proxim\Crypto;

/**
 * Class Hashing to manage hash and crypto of user (clients/merchants) passwords.
 *
 */
class Hashing
{
    /** @var array should contain hashing methods */
    private $hashMethods = array();

    /**
     * Check if it's the first function of the array that was used for hashing
     *
     * @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              Result of the verify function
     */
    public function isFirstHash($passwd, $hash, $staticSalt = PROX_COOKIE_KEY)
    {
        if (!count($this->hashMethods)) {
            $this->initHashMethods();
        }

        $closure = reset($this->hashMethods);

        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 = PROX_COOKIE_KEY)
    {
        if (!count($this->hashMethods)) {
            $this->initHashMethods();
        }

        foreach ($this->hashMethods 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 MuttStreet\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 = PROX_COOKIE_KEY)
    {
        if (!count($this->hashMethods)) {
            $this->initHashMethods();
        }

        $closure = reset($this->hashMethods);

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

    /**
     * prox_password_hash
     * 
     * @param string $password
     * @param string $salt
     * @return string
     */
    public function proxPasswordHash($password, $salt = null)
    {
        if ($salt === null) {
            $salt = substr(md5(uniqid(rand(), true)), 0, 9);
        } else {
            $salt = substr($salt, 0, 9);
        }

        return $salt . sha1($password . $salt);
    }

    /**
     * Init $hash_methods
     *
     * @return void
     */
    private function initHashMethods()
    {
        $this->hashMethods = array(
            'bcrypt' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return password_hash($passwd, PASSWORD_BCRYPT);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return password_verify($passwd, $hash);
                },
            ),
            'md5' => array(
                'option' => array(), 
                'hash' => function ($passwd, $staticSalt, $option) {
                    return $this->proxPasswordHash($passwd, $staticSalt);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return $hash === $this->proxPasswordHash($passwd,substr($hash,0,9));
                },
            )
        );
    }
}
