<?php

namespace App\Master;

use Carbon\Carbon;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManager;
use JetBrains\PhpStorm\Pure;

class LoginService
{
    /**
     * Handle the credential check
     *
     * @param string[] $credentials
     *
     * @return void
     */
    public function check(array $credentials)
    {
        $this->credentials = $credentials;
        if (!$this->isMtc()) {
            return;
        }

        $this->findLocalUser()
            ->verifyUser()
            ->updateUser();
    }

    /**
     * Perform a search for old emails in the system from the list
     *
     * @param array $emails
     * @return array|bool|mixed|null
     */
    public function filterOldUsers($emails = [])
    {
        return Http::timeout(3)
            ->post(
                $this->endpoint('api/staff/check-old'),
                [
                    'api_token' => config('mtc_login.api_token'),
                    'emails' => $emails,
                ]
            )->json();
    }

    /**
     * Determine if the email provided is our own.
     *
     * @return bool
     */
    #[Pure] public function isMtc()
    {
        return !Str::startsWith($this->credentials['email'], 'dev.')
            && (
                Str::contains($this->credentials['email'], '@mtcmedia.co.uk')
                || Str::contains($this->credentials['email'], '@mtc.co.uk')
            );
    }

    /**
     * Find if the user exists and if not, return a new model.
     *
     * @return self
     */
    protected function findLocalUser()
    {
        $this->user = App::make(config('auth.providers.users.model'))->newQuery()
            ->where('email', $this->credentials['email'])
            ->firstOrNew([]);

        return $this;
    }

    /**
     * Run a call against the API and store the decoded JSON response.
     *
     * @return self
     */
    protected function verifyUser()
    {
        $this->response = $this->isValidUser($this->credentials['email'], $this->credentials['password']);
        return $this;
    }

    /**
     * Update the user with the results of the response.
     *
     * @return void
     */
    protected function updateUser()
    {
        // No need to continue if user doesn't exist and bad response.
        if ($this->userWasNotVerified()) {
            return;
        }

        // Update pass to a random string if we have a bad response.
        $this->user->password = $this->response === null
            ? bcrypt(Str::random(40))
            : bcrypt($this->credentials['password']);

        if (!empty($this->response)) {
            $this->user->fill($this->response);
            $this->user->name = $this->response['name'];
            $this->user->requires_password_change = false;
            if (empty($this->user->profile_photo_path) && !empty($this->response['image'])) {
                $this->assignProfilePhoto($this->response['image']);
            }
        }

        $this->user->save();

        // Ensure mtc. users are assigned to the master role .
        if ($this->shouldAssignMasterRole()) {
            $this->user->assignRole(config('mtc_login.mtc_user_role'));
        }
    }

    /**
     * Check if user was verified
     *
     * @return bool
     */
    protected function userWasNotVerified()
    {
        return $this->response === false
            || ($this->user->exists == false && $this->response === null);
    }

    /**
     * Check if role should be assigned to user
     * This ensures role is set, users have roles and user doesn't have it already
     *
     * @return bool
     */
    protected function shouldAssignMasterRole()
    {
        return method_exists($this->user, 'hasRole')
            && !empty(config('mtc_login.mtc_user_role'))
            && $this->user->hasRole(config('mtc_login.mtc_user_role')) === false;
    }

    /**
     * Check if provided credentials are for a valid user
     *
     * @param $email
     * @param $password
     * @return array|bool|mixed|null
     */
    protected function isValidUser($email, $password)
    {
        $response = Http::timeout(3)
            ->post(
                $this->endpoint('api/staff_login.php'),
                [
                    'email' => $email,
                    'password' => $password
                ]
            );

        return $response->successful() ? $response->json() : null;
    }

    /**
     * Find the endpoint
     *
     * @param $path
     * @return string
     */
    protected function endpoint($path)
    {
        return rtrim(config('mtc_login.api_domain'), '/') . '/' . ltrim($path, '/');
    }

    /**
     * Assign profile image to user account
     *
     * @param string $imageUrl
     * @return void
     */
    protected function assignProfilePhoto(string $imageUrl)
    {
        $imageContent = file_get_contents($imageUrl);
        $fileName = 'profile-photos/' . Carbon::now()->format('U') . pathinfo($imageUrl, PATHINFO_BASENAME);
        $image = (new ImageManager(Config::get('media.image_manager_config', [])))
            ->make($imageContent)
            ->fit(config('media.default_thumbnail_size.width'), config('media.default_thumbnail_size.height'));

        Storage::disk(Config::get('filesystems.default'))
            ->put($fileName, $image->stream(), [
                'visibility' => 'public',
            ]);

        $this->user->profile_photo_path = $fileName;
    }
}
