<?php

namespace App\Repositories\Frontend\Auth;

use Carbon\Carbon;
use App\Models\Auth\User;
use Illuminate\Http\UploadedFile;
use App\Models\Auth\SocialAccount;
use Illuminate\Support\Facades\DB;
use App\Exceptions\GeneralException;
use App\Repositories\BaseRepository;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use App\Events\Frontend\Auth\UserConfirmed;
use App\Events\Frontend\Auth\UserProviderRegistered;
use App\Notifications\Frontend\Auth\UserNeedsConfirmation;

/**
 * Class UserRepository.
 */
class UserRepository extends BaseRepository
{
    /**
     * @return string
     */
    public function model()
    {
        return User::class;
    }

    /**
     * @param $token
     *
     * @return bool|\Illuminate\Database\Eloquent\Model
     */
    public function findByPasswordResetToken($token)
    {
        foreach (DB::table(config('auth.passwords.users.table'))->get() as $row) {
            if (password_verify($token, $row->token)) {
                return $this->getByColumn($row->email, 'email');
            }
        }

        return false;
    }

    /**
     * @param $uuid
     *
     * @return mixed
     * @throws GeneralException
     */
    public function findByUuid($uuid)
    {
        $user = $this->model
            ->uuid($uuid)
            ->first();

        if ($user instanceof $this->model) {
            return $user;
        }

        throw new GeneralException(__('exceptions.backend.access.users.not_found'));
    }
	
	public function findById($id)
    {
        $user = $this->model
            ->where('id', $id)
            ->first();

        if ($user instanceof $this->model) {
            return $user;
        }

        throw new GeneralException(__('exceptions.backend.access.users.not_found'));
    }


    /**
     * @param $code
     *
     * @return mixed
     * @throws GeneralException
     */
    public function findByConfirmationCode($code)
    {
        $user = $this->model
            ->where('confirmation_code', $code)
            ->first();

        if ($user instanceof $this->model) {
            return $user;
        }

        throw new GeneralException(__('exceptions.backend.access.users.not_found'));
    }

    /**
     * @param array $data
     *
     * @return \Illuminate\Database\Eloquent\Model|mixed
     * @throws \Exception
     * @throws \Throwable
     */
    public function create(array $data, $image = null, $document = null)
    {
        return DB::transaction(function () use ($data, $image, $document) {
            $avatar_location = null;
            if ($image) {
                $avatar_location = $image->store('/avatars', 'public');
                $img = Image::make($image->getRealPath());
                $img->resize(260, 260, function ($constraint) {
                    $constraint->aspectRatio();
                })->save($avatar_location);
            }

            $document_location = null;
            if ($document) {
                $document_location = $document->store('/document', 'public');
            }

            $user = parent::create([
                'first_name'        => $data['first_name'],
                'last_name'         => $data['last_name'],
                'email'             => $data['email'],
                'user_type'         => $data['user_type'],
                'confirmation_code' => md5(uniqid(mt_rand(), true)),
                'active'            => 1,
                'password'          => $data['password'],
                                    // If users require approval or needs to confirm email
                'confirmed'         => config('access.users.requires_approval') || config('access.users.confirm_email') ? 0 : 1,
                'avatar_type'       =>'storage',
                'avatar_location'   =>$avatar_location,
                'company_service_desc'=>(isset($data['company_service_desc'])) ? $data['company_service_desc']:null,
                'document_location'  =>$document_location,
            ]);

            if ($user) {
                /*
                 * Add the default site role to the new user
                 */
                $user->assignRole(config('access.users.default_role'));
            }

            /*
             * If users have to confirm their email and this is not a social account,
             * and the account does not require admin approval
             * send the confirmation email
             *
             * If this is a social account they are confirmed through the social provider by default
             */
            if (config('access.users.confirm_email')) {
                // Pretty much only if account approval is off, confirm email is on, and this isn't a social account.
                $user->notify(new UserNeedsConfirmation($user->confirmation_code));
            }

            /*
             * Return the user object
             */
            return $user;
        });
    }

    /**
     * @param       $id
     * @param array $input
     * @param bool|UploadedFile  $image
     *
     * @return array|bool
     * @throws GeneralException
     */
    public function update($id, array $input, $image = '', $document = '')
    {
        $user = $this->getById($id);
        $user->first_name = $input['first_name'];
        $user->last_name = $input['last_name'];
        if (array_key_exists('company_service_desc', $input) ) {
            $user->company_service_desc = $input['company_service_desc'];
        }
        
        // Upload profile image if necessary
        if ($image) {
            $user->avatar_location = $image->store('/avatars', 'public');
            Storage::disk('public')->delete(auth()->user()->avatar_location);
        }

        if ($document) {
            $user->document_location = $document->store('/document', 'public');
            Storage::disk('public')->delete(auth()->user()->document_location);
        }

        $user->save();
        $updateId = $user->id;
        return $updateId;
    }

    /**
     * @param      $input
     * @param bool $expired
     *
     * @return bool
     * @throws GeneralException
     */
    public function updatePassword($input, $expired = false)
    {
        $user = $this->getById(auth()->id());

        if (Hash::check($input['old_password'], $user->password)) {
            if ($expired) {
                $user->password_changed_at = Carbon::now()->toDateTimeString();
            }

            return $user->update(['password' => $input['password']]);
        }

        throw new GeneralException(__('exceptions.frontend.auth.password.change_mismatch'));

    }

    /**
     * @param $code
     *
     * @return bool
     * @throws GeneralException
     */
    public function confirm($code)
    {
        $user = $this->findByConfirmationCode($code);

        if ($user->confirmed == 1) {
            throw new GeneralException(__('exceptions.frontend.auth.confirmation.already_confirmed'));
        }

        if ($user->confirmation_code == $code) {
            $user->confirmed = 1;

            event(new UserConfirmed($user));

            return $user->save();
        }

        throw new GeneralException(__('exceptions.frontend.auth.confirmation.mismatch'));
    }

    /**
     * @param $data
     * @param $provider
     *
     * @return mixed
     * @throws GeneralException
     */
    public function findOrCreateProvider($data, $provider)
    {
        // User email may not provided.
        $user_email = $data->email ?: "{$data->id}@{$provider}.com";

        // Check to see if there is a user with this email first.
        $user = $this->getByColumn($user_email, 'email');

        /*
         * If the user does not exist create them
         * The true flag indicate that it is a social account
         * Which triggers the script to use some default values in the create method
         */
        if (! $user) {
            // Registration is not enabled
            if (! config('access.registration')) {
                throw new GeneralException(__('exceptions.frontend.auth.registration_disabled'));
            }

            // Get users first name and last name from their full name
            $nameParts = $this->getNameParts($data->getName());

            $user = parent::create([
                'first_name'  => $nameParts['first_name'],
                'last_name'  => $nameParts['last_name'],
                'email' => $user_email,
                'active' => 1,
                'confirmed' => 1,
                'password' => null,
                'avatar_type' => $provider,
            ]);

            event(new UserProviderRegistered($user));
        }

        // See if the user has logged in with this social account before
        if (! $user->hasProvider($provider)) {
            // Gather the provider data for saving and associate it with the user
            $user->providers()->save(new SocialAccount([
                'provider'    => $provider,
                'provider_id' => $data->id,
                'token'       => $data->token,
                'avatar'      => $data->avatar,
            ]));
        } else {
            // Update the users information, token and avatar can be updated.
            $user->providers()->update([
                'token'       => $data->token,
                'avatar'      => $data->avatar,
            ]);

            $user->avatar_type = $provider;
            $user->update();
        }

        // Return the user object
        return $user;
    }

    /**
     * @param $fullName
     *
     * @return array
     */
    protected function getNameParts($fullName)
    {
        $parts = array_values(array_filter(explode(' ', $fullName)));
        $size = count($parts);
        $result = [];

        if (empty($parts)) {
            $result['first_name'] = null;
            $result['last_name'] = null;
        }

        if (! empty($parts) && $size == 1) {
            $result['first_name'] = $parts[0];
            $result['last_name'] = null;
        }

        if (! empty($parts) && $size >= 2) {
            $result['first_name'] = $parts[0];
            $result['last_name'] = $parts[1];
        }

        return $result;
    }


	public function getServiceProviderOnCityService($city_id,$service_id, $catId){
        //echo $city_id.'|'.$service_id.'|'.$catId;
        if ($city_id != 0 &&  $service_id != 0) {
            return User::leftJoin('service_provider_to_cities', function ($join) {
                        $join->on('users.id', '=', 'service_provider_to_cities.user_id');
                        })->leftJoin('service_provider_to_services', function ($join) {
                        $join->on('users.id', '=', 'service_provider_to_services.user_id');
                        })
                        ->where('service_provider_to_services.service_id', $service_id)
                        ->where('service_provider_to_cities.city_id', $city_id)
                        ->where('users.user_type', 3)
                        ->where('users.active', 1)
                        ->whereNull('users.deleted_at')
                        ->whereNull('service_provider_to_services.deleted_at')
                        ->whereNull('service_provider_to_cities.deleted_at')
                        ->get();
                 
        } elseif ($service_id != 0) {
            return User::leftJoin('service_provider_to_services', function ($join) {
                        $join->on('users.id', '=', 'service_provider_to_services.user_id');
                        })
                        ->where('service_provider_to_services.service_id', $service_id)
                        ->where('users.user_type', 3)
                        ->where('users.active', 1)
                        ->whereNull('users.deleted_at')
                        ->whereNull('service_provider_to_services.deleted_at')
                        ->get();
        } elseif ($city_id != 0 ) { 
            return User::leftJoin('service_provider_to_cities', function ($join) {
                        $join->on('users.id', '=', 'service_provider_to_cities.user_id');
                        })
                        
                        ->where('service_provider_to_cities.city_id', $city_id)
                        ->where('users.user_type', 3)
                        ->where('users.active', 1)
                        ->whereNull('users.deleted_at')
                        ->whereNull('service_provider_to_cities.deleted_at')
                        ->get();

        } elseif ($catId != 0) {
            return User::leftJoin('service_provider_to_services', function ($join) {
                        $join->on('users.id', '=', 'service_provider_to_services.user_id');
                        })
                        ->where('service_provider_to_services.service_id', $catId)
                        ->where('users.user_type', 3)
                        ->where('users.active', 1)
                        ->whereNull('users.deleted_at')
                        ->whereNull('service_provider_to_services.deleted_at')
                        ->get();
        } else {
            return User::where('users.user_type', 3)
                        ->where('users.active', 1)
                        ->whereNull('users.deleted_at')
                        ->get();

        }
	}

    /**
     * @param array $where
     * @param array $input
     *
     * @return array|bool
     * @throws GeneralException
     */
    public function updateByCondition(array $where, array $input)
    {
        $updated = $this->model->where($where)
            ->update($input);
        return $updated;
    }
}
