<?php

namespace Mnv\Core;

use Mnv\Core\Uploads\ImageSizes;
use Mnv\Models\Interfaces\IModel;

/**
 * Class Model
 * @package Mnv\Core
 */
abstract class Model implements IModel
{
    /**
     * Таблица, связанная с моделью.
     *
     * @var string
     */
    protected string $table = '';

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

    /**
     * Первичный ключ для модели.
     *
     * @var string
     */
    protected string $primaryKey = 'id';

    /**
     * @var string
     */
    protected string $orderBy = '';

    /**
     * @var array
     */
    public array $all_columns = [];
    /**
     * @var string
     */
    protected string $columns = '*';

    /**
     * Указывает, существует ли модель.
     *
     * @var bool
     */
    public $exists = false;

    /**
     * Идентификатор модели
     *
     * @var int|null
     */
    public $id;

    /**
     * Массив модели
     *
     * @var array
     */
    public $data = [];

    /**
     * @var array
     */
    public array $filter = [];

    /**
     * @var string|null
     */
    public ?string $status;

    /**
     * Кол-во
     * @var int
     */
    public int $total = 0;

    /**
     * @var array|null
     */
    public ?array $result = [];

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

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

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



    /**
     * Установить таблицу, связанную с моделью.
     *
     * @param string $table
     * @return $this
     */
    public function setTable(string $table): Model
    {
        $this->table = $table;

        return $this;
    }

    /**
     * Получить таблицу, связанную с моделью.
     *
     * @return string
     */
    public function getTable(): string
    {
        return $this->table ?? strtolower(class_basename($this));
    }

    /**
     * @param $columns
     */
    public function setColumn($columns): void
    {
        if (!empty($columns)) {
            if (is_array($columns)) {
                if (isset($columns)) {
                        unset($columns[array_search('image', $columns)]);
                }
                $this->columns = implode(", ", $columns);
            } else {
                $this->columns = $columns;
            }
        } else {
            $this->columns = '*';
        }
    }

    /**
     * @return string
     */
    public function getColumn(): string
    {
        return $this->columns;
    }

    /**
     * @param $orderBy
     */
    public function setOrderBy($orderBy): void
    {
        $this->orderBy = $orderBy;
    }

    /**
     * @return string
     */
    public function getOrderBy(): string
    {
        return $this->orderBy;
    }

    /**
     * Получить все элементы, связанные с моделью.
     *
     * @param int $limit
     * @param int $page
     * @return mixed
     */
    public function all(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;

            $this->orderBy = $this->sortBy .' ' . strtoupper($this->sortOrder);
        }

        if (!empty($this->orderBy)) {
            connect($this->table)->orderBy($this->orderBy);
        }

        $result = connect($this->table)->select($this->columns)->pagination($limit, $page)->getAll('array');
//        print_r(connect()->getQuery().PHP_EOL);
        return $result;
    }

    public function total(): void
    {
        $this->total = (int)connect($this->table)->count('*', 'count')->getValue();
    }

    public function get(): ?array
    {
        return connect($this->table)->where($this->primaryKey,  $this->id)->get('array');
    }

    public function edit(): Model
    {
       !empty($this->id) && $this->data = $this->get();

        return $this;
    }

    /**
     * @param string|null $fileName
     * @return mixed
     */
   // abstract public function checkFileName(string $fileName);

    /**
     * @param array $data
     * @return bool|int|string|void|null
     */
    public function insert(array $data)
    {
        return connect($this->table)->insert($data);
    }

    /**
     * @param array $data
     * @return bool
     */
    public function update(array $data): bool
    {
        return !empty($this->id) && connect($this->table)->where($this->primaryKey, $this->id)->update($data);
    }


    /** Изменить статус */
    public function status(): bool
    {
        if (!empty($this->id) && $oldStatus = connect($this->table)->select('status')->where($this->primaryKey, $this->id)->getValue()) {
            $update['status'] = ($oldStatus == 'V') ? 'H' : 'V';
            connect($this->table)->where($this->primaryKey, $this->id)->update($update);
            $this->status = $update['status'];

            return true;
        }

        return false;
    }


    public function remove(): bool
    {
        return !empty($this->id) && connect($this->table)->where($this->primaryKey, $this->id)->delete();
    }

    protected function getMaxValue(string $field, ?string $name = null)
    {
        return connect($this->table)->max($field, $name)->getValue();
    }

    /**
     * получение информации о пользователях, создавших и изменивших контент
     * getting info about users who created and modified the content
     */
    public function gettingInfoAboutUsers(): Model
    {
        if (isset($this->data['addedBy'], $this->data['modifiedBy'])) {
            $managers = connect('users')->select('userId, loginName')->in('userId', [$this->data['addedBy'], $this->data['modifiedBy']])->indexKey('userId')->getAllIndexes('array');
            $this->data['addedBy']    = !empty($managers[$this->data['addedBy']]) ? $managers[$this->data['addedBy']] : unknownUser();
            $this->data['modifiedBy'] = !empty($managers[$this->data['modifiedBy']]) ? $managers[$this->data['modifiedBy']] : unknownUser();
            $this->data['addedOn']    = adjustTime($this->data['addedOn'], false, 'd.m.Y H:i');
            $this->data['modifiedOn'] = adjustTime($this->data['modifiedOn'], false, 'd.m.Y H:i');
            if (isset($this->data['publishedOn']))
                $this->data['publishedOn'] = adjustTime($this->data['publishedOn']);
        }

        return $this;
    }

    /** РАБОТА С ФАЙЛАМИ / ИЗОБРАЖЕНИЕМ */

    protected function getFileInfo($fileId): ?array
    {
       return connect('files')->where('fileId', $fileId)->get('array');
    }

    /** получить все из таблицы images модели  */
    public function getFiles(): Model
    {
        if (!empty($this->table_image) && $images = connect($this->table_image)->where($this->primaryKey, $this->id)->orderBy('orderBy ASC')->getAll('array')) {
            collect($images)->map(function ($item)  {
                if ($file = $this->getFileInfo($item['fileId'])) {
                    if ($item['type'] == 'general') {
                        $this->data['image'] = ImageSizes::init()->get($item, $file);
                    } elseif ($item['type'] == 'gallery') {
                        $this->data['gallery'][] = ImageSizes::init()->get($item, $file);
                    } elseif ($item['type'] == 'songs') {
                        $this->data['songs'][] = ImageSizes::init()->get($item, $file);
                    } else {
                        $this->data['docs'][] = ImageSizes::init()->get($item, $file);
                    }
                }
            })->toArray();
        }

//        print_r($this->data);
        return $this;
    }

    /**
     * получить основное изображение
     *
     * @param $modelId
     * @return array|null
     */
    public function getMainImage($modelId): ?array
    {
        if (!empty($this->table_image)) {
            if ($file = connect($this->table_image)->usingJoin('files', 'fileId')->where($this->primaryKey, $modelId)->where('type', 'general')->get('array')) {
                return ImageSizes::init()->get(null, $file);
            }
        }

        return null;
    }

    /**
     * Удаление основной картинки
     * @param $imageId
     * @return bool
     */
    public function deleteFile($imageId): bool
    {
        if (connect($this->table_image)->where('imageId', $imageId)->delete())
            return true;

        return false;
    }

    /**
     * Добавление или замена информации у картинки в галереи
     *
     * @param $imageId
     * @param $picture
     * @return bool
     */
    public function editPictureInfo($imageId, $picture): bool
    {
        $updateParams = [
            'title'         => $picture['title'],
            'alias'         => $picture['alias'],
            'description'   => $picture['description'],
            'link'          => $picture['link'],
            'position'      => $picture['position']
        ];

        if (connect($this->table_image)->where('imageId', $imageId)->update($updateParams)) {
            $this->result = connect($this->table_image)->where('imageId', $imageId)->get('array');

            return true;
        }

        return false;
    }

    /**
     * Сортировать галерею
     *
     * @param $imageId
     * @param $index
     * @return bool
     */
    public function sortPictures($imageId, $index): bool
    {
        if (!empty($imageId) && !empty($index)) {
            connect($this->table_image)->where('imageId', $imageId)->update(['orderBy' => $index]);

            return true;
        }

        return false;
    }

    /**
     * Сортировать галерею
     *
     * @param $imageId
     * @param $index
     * @return bool
     */
    public function sortSongs($imageId, $index): bool
    {
        if (!empty($imageId) && !empty($index)) {
            connect($this->table_image)->where('imageId', $imageId)->update(['orderBy' => $index]);

            return true;
        }

        return false;
    }

    /**
     * Добавление или замена информации у картинки в галереи
     *
     * @param $imageId
     * @param $picture
     * @return bool
     */
    public function editSongInfo($imageId, $picture): bool
    {
        $updateParams = [
            'title' => $picture['title']
        ];

        if (connect($this->table_image)->where('imageId', $imageId)->update($updateParams)) {
            $this->result = connect($this->table_image)->where('imageId', $imageId)->get('array');

            return true;
        }

        return false;
    }

    /**
     * Добавление картинки
     *
     * @param int $modelId
     * @param array $image
     * @return bool
     */
    public function addMainImage(int $modelId, array $image): bool
    {
        if ($file = $this->getFileInfo($image['fileId'])) {

            if ($imageId = connect($this->table_image)->where('type', 'general')->where($this->primaryKey, $modelId)->select('imageId')->getValue()) {
                connect($this->table_image)->where('imageId',$imageId)->where($this->primaryKey, $modelId)->delete();
            }

            $imageUpload = [
                $this->primaryKey   => $modelId,
                'fileId'            => $file['fileId'],
                'type'              => 'general',
                'position'          => 'default',
                'orderBy'           => 0
            ];

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

        return false;
    }

    /**
     * Загрузка картинок в галерею или добавление документов
     *
     * @param int $modelId
     * @param array $images
     * @param string $type
     * @return bool
     */
    public function addGalleryAndDocuments(int $modelId, array $images, string $type): bool
    {
        if (!empty($images[$type])) {
            $idx = 0;
            if ($order = connect($this->table_image)->where($this->primaryKey, $modelId)->where('type', $type)->max('orderBy')->getValue())
                $idx = $order;

            foreach ($images[$type] as $image) {
                $idx++;
                $imageUpload = [
                    $this->primaryKey   => $modelId,
                    'fileId'            => $image['fileId'],
                    'type'              => $type,
                    'position'          => 'default',
                    'orderBy'           => $idx
                ];

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

        return false;
    }

}