<?php

namespace Mnv\Models\Users;

use Mnv\Core\SortTable;
use Mnv\Core\Uploads\ImageSizes;

abstract class AbstractUser implements UserInterface
{

    /**
     * Таблица, связанная с моделью.
     *
     * @var string
     */
    protected string $table = 'users';

    /**
     * Таблица файлов, связанная с моделью.
     *
     * @var string
     */
    protected string $table_image = 'user_images';
    /**
     * Первичный ключ для модели.
     *
     * @var string
     */
    protected string $primaryKey = 'userId';

    /**
     * @var int $userId
     */
    public int $userId;

    /**
     * пользователь
     * @var $user
     */
    public $user = [];

    /**
     * кол-во пользователей
     * @var int $total
     */
    public int $total = 0;

    /**
     * @var $oldUser
     */
    public $oldUser = [];

    /** @var array  */
    public array $filter = array();


    /** @var string  */
    public string $sortTableId = '';

    /** @var string  */
    public string $sortBy = '';

    /** @var string  */
    public string $sortOrder = '';

    protected function sorting()
    {
        if (!empty($this->filter['query'])) {
            connect()->grouped(function($q) {
                $q->like('email', "%" . $this->filter['query'] . "%")
                    ->orLike('loginName', "%" . $this->filter['query'] . "%")
                    ->orLike('fullName',"%" . $this->filter['query'] . "%")
                    ->orLike('firstName',"%" . $this->filter['query'] . "%")
                    ->orLike('lastName',"%" . $this->filter['query'] . "%")
                    ->orLike('phone',"%" . $this->filter['query'] . "%");
            });
        }
        if (!empty($this->filter['status'])) connect()->where('status', $this->filter['status']);

        if (!empty($this->filter['userType'])) {
            connect()->where('userType', $this->filter['userType']);
        }
    }

    /**
     * Получение всех пользователей
     *
     * @param string|null $orderBy
     * @param int $limit
     * @param int $page
     */
    public function all(?string $orderBy, int $limit, int $page)
    {
        $sortable = SortTable::init()->getSort($this->sortTableId);
        if (!empty($sortable)) {
            $this->sortBy = $sortable[$this->sortTableId]['last_sort_by'] ?? null;
            $this->sortOrder = $sortable[$this->sortTableId]['last_sort_order'] ?? null;

            $orderBy = $this->sortBy .' ' . strtoupper($this->sortOrder);
        }
        /** Фильтровать пользователей */
        $this->sorting();

        return connect($this->table)->pagination($limit, $page)->orderBy($orderBy)->getAll('array');

    }

    /**
     * Получение кол-во пользователей
     */
    public function total(): void
    {
        /** Фильтровать пользователей */
        $this->sorting();

        $this->total = (int) connect($this->table)->count('*', 'count')->getValue();
    }


    /** Получить пользователя */
    public function get(?string $userType = null): void
    {
        if (!empty($userType)) connect()->where('userType', $userType);
        $this->user = connect($this->table)->where($this->primaryKey, $this->userId)->get('array');
    }

    /**
     * Проверка кол-во разработчиков
     *
     * @param $userType
     * @return bool
     */
    protected function getUserByRole($userType) : bool
    {
        $users = connect($this->table)->where('userType', $userType)->limit(2)->getAll();
        return \count($users) > 1;
    }


    /**
     * Удаление пользователя
     */
    protected function removeUser() : bool
    {
        if (connect($this->table)->where($this->primaryKey, $this->userId)->delete()) {
            connect('comments')->where('visitorId', $this->userId)->delete();
            connect($this->table_image)->where($this->primaryKey, $this->userId)->delete();

            return true;
        }
        return false;
    }

    /**
     * Обновление статуса пользователя
     * @return bool
     */
    protected function approveUser() : bool
    {
        return !empty($this->userId) && connect($this->table)->where($this->primaryKey, $this->userId)->update(['status' => 1]);
    }

    /**
     * Добавление нового пользователя
     *
     * @param array $data
     * @return bool
     */
    public function insert(array $data) : bool
    {
        if ($this->userId = (int) connect($this->table)->insert($data)) return true;

        return false;
    }

    /**
     * Изменение данных пользователя
     *
     * @param array $data
     * @return bool
     */
    public function update(array $data) : bool
    {
        return connect($this->table)->where($this->primaryKey, $this->userId)->update($data);
    }


    /**
     * Проверка существует ли такой менеджер или да то возвращаем его
     *
     * @param int $userId
     */
    public function getOldDataUser(int $userId) : void
    {
        $this->oldUser = connect($this->table)->where($this->primaryKey, $userId)->get('array');
    }

    /**
     * Проверяем существует ли нововведений логин в базе данных
     * @param $loginName
     */
    /**
     * @param $loginName
     * @return mixed|string|null
     */
    public function checkExistenceLoginName($loginName): ?string
    {
        if (!empty($this->userId)) connect()->where($this->primaryKey,'<>', $this->userId);
        if ($fileName = connect($this->table)->select('loginName')->where('LOWER(loginName)', $loginName)->getValue())
            return $fileName;

        return null;
    }
    /**
     * Проверяем существует ли нововведений логин в базе данных
     *
     * @param $manager
     * @return bool
     */
    public function existUserLoginName($manager) : bool
    {
        if (connect($this->table)->where('loginName = ? AND userId <> ?', [$manager->loginName, $manager->userId])->get())  return true;

        return false;
    }

    /**
     * Проверяем существует ли другой пользователь с указанными правами доступа администратор `[Role::DEVELOPER, Role::ADMIN]`
     * если он один такой то запрет на изменение
     * всегда должен существовать один пользователь с правами `[Role::DEVELOPER, Role::ADMIN]`
     *
     * @param array $manager
     * @param string $userType
     * @return bool
     */
    public function accessLevelRole(array $manager, string $userType) : bool
    {
        if (!connect($this->table)->where('userId <> ? AND userType = ?', [$manager['userId'], $userType])->get())  return true;

        return false;
    }

    /**
     * Удаление фото
     *
     * @return bool
     */
    /**
     * @param int $userId
     * @return bool
     */
    public function removeUserImage(int $userId) : bool
    {
        if (!empty($userId)) {
            connect($this->table_image)->where($this->primaryKey,  $userId)->delete();
            return true;
        }

        return false;
    }

    /**
     * Проверка на совпадение loginName
     * @param string $loginName
     * @return string|null
     */
    public function checkLogin(string $loginName): ?string
    {
        if (!empty($this->userId)) connect()->where($this->primaryKey,'<>', $this->userId);
        if ($loginName = connect($this->table)->select('loginName')->where('loginName', $loginName)->getValue()) {
            return $loginName;
        }

        return null;
    }

    /**
     * Проверка на совпадение email
     * @param string $email
     * @return string|null
     */
    public function checkEmailUser(string $email): ?string
    {
        if (!empty($this->userId)) connect()->where($this->primaryKey,'<>', $this->userId);
        if ($email = connect($this->table)->select('email')->where('email', $email)->getValue()) {
            return $email;
        }

        return null;
    }

    /**
     * Получение пароля
     * @param $userId
     * @return bool|int
     */
    public function getUserOldPassword($userId)
    {
        return !empty($userId) && connect($this->table)->select('password')->where($this->primaryKey, $userId)->getValue();
    }


    /**
     * Добавление основной картинки к контенту
     *
     * @param $userId
     * @param $images
     * @return bool
     */
    public function general($userId, $images): bool
    {
        $imageUpload = array_filter([
            'userId' => $userId,
            'fileId'    => $images['fileId'],
            'type'      => 'general',
            'orderBy'   => 0
        ]);

        if ($imageId = connect($this->table_image)->select('imageId')->where('type','general')->where($this->primaryKey, $userId)->getValue()) {
            $imageUpload['imageId'] = $imageId;
        }

        if (connect($this->table_image)->replace($imageUpload)) {
            return true;
        }

        return false;
    }

    /**
     * @param int $userId
     * @return array|null
     */
    public function getFile(int $userId): ?array
    {

        if ($file = connect($this->table_image)->table($this->table_image)->usingJoin('files', 'fileId')->select('*')->where('type', 'general')->where($this->primaryKey, $userId)->get('array')) {
            return ImageSizes::init()->get(null, $file);
        }

        return null;
    }

    /**
     * получать основной картинки
     */
    public function getFiles(): void
    {
        if (!empty($this->userId) && !empty($this->user)) {
            if ($images = connect($this->table_image)->select('*')->where($this->primaryKey, $this->userId)->indexKey('imageId')->orderBy('orderBy')->getAllIndexes('array')) {
                foreach ($images as $imageId => $image) {
                    if ($file = connect('files')->where('fileId', $image['fileId'])->get('array')) {
                        if ($image['type'] === 'general') {
                            $this->user['image'] = ImageSizes::init()->get($image, $file);
                        } elseif ($image['type'] === 'gallery') {
                            $this->user['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                        } else {
                            $this->user['docs'][$imageId] = ImageSizes::init()->get($image, $file);
                        }
                    }
                }
            }
        }
    }

}
