<?php

/*
 * This file is part of the AuthStack project.
 *
 * (c) Buckhill Ltd <development@buckhill.co.uk>
 *
 * This source file is subject to the Buckhill license that is bundled
 * with this source code in the file LICENSE.
 */

namespace AuthStack\TwoFactor\Collection;

use Illuminate\Support\Collection;
use AuthStack\TwoFactor\Model\MFAKey;
use AuthStack\TwoFactor\Model\MFAMode;
use AuthStack\TwoFactor\Model\SecurityKey;
use AuthStack\TwoFactor\Model\ViewSecurityKey;


class KeyCollection implements KeyCollectionInterface
{
    protected $collection;
    protected $user_id;
    protected $otp_verification_msg;

    /**
     * Finds all keys that belong to user identified by $id and loads them into the collection
     *
     * @param $id
     * @return static
     */
    public static function loadForUser($id)
    {
        $ids = SecurityKey::where("user_id", $id)->pluck('key_id')->toArray();

        $mfakeys = MFAKey::whereIn('id', $ids)->get();

        $me = new static;

        $me->user_id = $id;

        return $me->setCollection(collect($mfakeys));
    }

    /**
     * @param $otp
     * @return bool
     */
    public function verifyOTP($otp)
    {
        if(!$this->hasOTP())
        {
            $this->setOTPError('User has no security keys that produce OTPs associated with their account, skipping the check.');

            return false;
        }

        $keys = $this->getOTPKeys();

        $result = false;

        foreach($keys as $key)
        {
            /** @var $key MFAKey */

            $result = $key->verify($otp);

            if($result)
            {
                $key->synchronize();

                break;
            }
        }

        return $result;
    }

    /**
     * @return Collection
     */
    public function getKeyCollection()
    {
        return $this->collection;
    }

    /**
     * @return int
     */
    public function count()
    {
        return $this->getKeyCollection()->count();
    }

    /**
     * @return bool
     */
    public function hasU2F()
    {
        return (bool)$this->getKeyCollection()->where('mode_id', MFAMode::MODE_U2F)->count();
    }

    /**
     * @return bool
     */
    public function hasOTP()
    {
        return (bool)$this->getOTPKeys()->count();
    }

    /**
     * @return Collection
     */
    public function getOTPKeys()
    {
        return $this
            ->getKeyCollection()
            ->whereIn('mode_id', [
                MFAMode::MODE_RFC4226,
                MFAMode::MODE_RFC6238,
                MFAMode::MODE_YUBIKEY,
                MFAMode::MODE_YUBIKEY_OATH
            ]);
    }

    /**
     * @return array
     */
    public function toArray()
    {
        return $this->getKeyCollection()->toArray();
    }


    /**
     * @param null $user_id
     * @return array
     */
    public function getKeyList($user_id = null)
    {
        $user_id = is_null($user_id) ? $this->user_id : $user_id;

        return ViewSecurityKey::forUser($user_id);
    }

    /**
     * @param Collection $collection
     * @return $this
     */
    protected function setCollection(Collection $collection)
    {
        $this->collection = $collection;

        return $this;
    }

    /**
     * @param $msg
     * @return $this
     */
    protected function setOTPError($msg)
    {
        $this->otp_verification_msg = $msg;

        return $this;
    }
}