<?php

declare(strict_types=1);

namespace kodorvan\surikov\controllers;

// The project
use kodorvan\surikov\controllers\core,
kodorvan\surikov\models\account,
kodorvan\surikov\models\publication;

// Framework for PHP
use mirzaev\minimal\http\enumerations\content,
mirzaev\minimal\http\enumerations\status;

/**
 * Publications controller
 *
 * @package kodorvan\surikov\controllers
 *
 * @param array $errors Registry of errors
 *
 * @method null index() Publications page
 * @method null write() Write
 * @method null read(int|string|null $identifier, int|string|null $page) Read
 * @method null delete(int|string|null $identifier) Delete
 * @method null rotate(int|string|null $identifier, int|string|null $page) Rotate
 *
 * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
final class publications extends core
{
    /**
     * Errors
     *
     * @var array $errors Registry of errors
     */
    protected array $errors = [
        'system' => [],
        'account' => [],
        'publications' => []
    ];

    /**
     * Data verification
     *
     * @param string|null $title Title if the publication
     * @param string|null $content Content if the publication
     *
     * @return null
     */
    private function data(string|null $title, string|null $content): bool
    {
        //Removing spaces
        $title = trim($title ?? '');
        $content = trim($content ?? '');

        //Checking for the existence of data
        if (empty($title)) {

            //Error recording
            $this->errors['publications'][] = 'Заголовок не может быть пустым';

            // Exit (failed)
            return false;
        }

        //Removing the shielding "/"
        $title = stripslashes($title);
        $content = stripslashes($content);

        //Checking the length
        if (mb_strlen($title) > 255) {

            //Error recording
            $this->errors['publications'][] = 'Заголовок слишком длинный';

            // Exit (failed)
            return false;
        }

        //Checking the length
        if (mb_strlen($content) > 1000) {

            //Error recording
            $this->errors['publications'][] = 'Содержание слишком большое!';

            // Exit (failed)
            return false;
        }

        // Exit (success)
        return true;
    }

    /**
     * Processing of uploaded files
     * 
     * @return array 
     */
    private function files($identifier): array|null
    {
        //Presence of uploaded files
        if (!empty($_FILES['publications']['tmp_name'])) {

            //Array for storing data
            $files = [];

            // Path to the directory to save
            $dir = \STORAGE . DIRECTORY_SEPARATOR . 'publications' . DIRECTORY_SEPARATOR;

            //Maximum file size (5MB)
            $size = 5 * 1024 * 1024;

            // Acceptable MIME types
            $types = ['image/jpeg', 'image/png', 'image/gif'];

            //Checking if the directory exists and creating it if it doesn't
            if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
                $this->errors['publications'][] = 'Не удалось создать путь для изображения';

                // Exit (failed)
                return null;
            }

            //Verifying write permissions to a directory
            if (!is_writable($dir)) {
                $this->errors['publications'][] = 'Директория недоступна для записи';

                // Exit (failed)
                return null;
            }

            // Processing of each file  
            foreach ($_FILES['publications']['tmp_name'] as $key => $tmp) {

                /// Checking the upload to a temporary server
                if (empty($tmp) || $_FILES['publications']['error'][$key] !== UPLOAD_ERR_OK) {
                    $this->errors['publications'][] = 'Ошибка загрузки файла ';
                    continue;
                }

                // Checking the file size
                if ($_FILES['publications']['size'][$key] > $size) {
                    $this->errors['publications'][] = 'Размер изображения не должен превышать 5MB';
                    continue;
                }

                //// Defining the MIME type of a file
                $type = mime_content_type($tmp);

                // Checking the file type validity
                if (!in_array($type, $types)) {
                    $this->errors['publications'][] = 'Недопустимый тип файла';
                    continue;
                }

                // Full path to save
                $path = trim($dir . $identifier . '.png');

                //// Moving a file from a temporary directory
                if (!move_uploaded_file($tmp, $path)) {
                    $this->errors['publications'][] = 'Ошибка при загрузке файла на сервер: ' . $_FILES['publications']['name'][$key];
                    continue;
                }

                // checking the existence of the file after moving
                if (!file_exists($path)) {
                    $this->erroFrs['publications'][] = 'Файл не был сохранен: ' . $identifier;
                    continue;
                }

                // Collecting information about a file
                $files[] = [
                    'path' => $path,
                    'name' => $identifier,
                    'size' => $_FILES['publications']['size'][$key],
                    'type' => $type
                ];

            }

            //Exit (Succes)
            return $files;
        }

        //Exit (Failed)
        return [];
    }

    /**
     * Read
     *
     * Read the publication image
     *
     * @param int|string|null $identifier Identifier of the publication
     *
     * @return string|null The publication image
     */
    public function read(int|string|null $identifier = null): ?string
    {
        // Normalizing the identifier argument
        $identifier = (int) $identifier;

        // Initializing the publication file path
        $file = \STORAGE . DIRECTORY_SEPARATOR . 'publications' . DIRECTORY_SEPARATOR . $identifier . '.png';

        // Reading the file
        $stream = fopen($file, 'rb');

        if (file_exists($file)) {
            // Found the publication page file

            // Initializing headers
            header('Content-Type: image/png');
            header('Content-Length: ' . filesize($file));

            // Cleaning the output buffer
            fpassthru($stream);
        }

        // Exit (fail)
        return null;
    }

    /**
     * Publications page
     *
     * @param int|string $page Page if the publication
     *
     * @return null
     */
    public function index(
        int|string $page = 1,
    ): null {
        // Reading publications
        $this->view->publications = publication::read(expressions: ['active' => true], limit: 30, page: $page, sort: '`created` DESC');

        if (str_contains($this->request->headers['accept'] ?? '', content::any->value)) {
            // Request for any response

            // Render page
            $page = $this->view->render('main/index.html');

            // Sending response
            $this->response
                ->start()
                ->clean()
                ->sse()
                ->write($page)
                ->validate($this->request)
                    ?->body()
                ->end();

            // Deinitializing rendered page
            unset($page);

            // Exit (success)
            return null;
        }
    }

    /**
     * Write
     *
     * Import publications into the storage and the database
     * @param string|null $title Title if the publication
     * @param string|null $content Content if the publication
     * @param int|bool $active Relevance if the publication
     * 
     * @return null
     */
    public function write(string|null $title = null, string|null $content = null, int|bool $active = 1): null
    {
        // Initialized account and authorized to publications
        if ($this->account->access('publications')) {

            //Data verification
            if ($this->data($title, $content)) {

                $identifier = 0;

                //Processing uploaded files
                $identifier = publication::write($title, $content, $active, $this->account->identifier, $this->errors['publications']);

                if ($identifier) {

                    // Recording a publication
                    $status = true;

                    //Image verification
                    $this->files($identifier);
                }

            } else {
                $status = false;
                // Data verification failed
            }
        }

        // Reading publications
        $this->view->publication = publication::read(expressions: ['account' => (int) $this->account->identifier], sort: '`created` DESC')[0] ?? null;

        // Redirecting 
        $publications = $this->view->render('publication.html');

        // Sending response
        $this->response
            ->start()
            ->clean()
            ->sse()
            ->write($publications)
            ->validate($this->request)
                ?->body()
            ->end();

        // Deinitializing rendered page
        unset($publications);

        // Exit (success)
        return null;
    }

    /**
     * Update
     * 
     * Update a post in the database and images
     * 
     * @param string|null $title Post title
     * @param string|null $content Post content 
     * @param int|string|null $identifier Post identifier
     * 
     * @return null
     */
    public function update(string|null $title = null, string|null $content = null, int|string|null $identifier = null): null
    {
        // Initialized account and authorized to publications
        if ($this->account->access('publications')) {

            //Converting an identifier to Int
            $identifier = (int) $identifier;

            //Data verification 
            if ($this->data($title, $content) && $identifier > 0) {

                //Image verification
                $files = $this->files($identifier);

                if (publication::update($identifier, $title, $content, $files, $this->errors['publications'])) {
                    $status = true;
                    //Updating the publication

                } else {
                    $status = false;
                    //Not updating the publication
                }

            } else {
                $status = false;
                //Data verification failed
            }
        }

        // Reading publications
        $this->view->publication = publication::read(expressions: ['account' => (int) $this->account->identifier], sort: '`created` DESC')[0] ?? null;

        // Redirecting 
        $publications = $this->view->render('publication.html');

        // Sending response
        $this->response
            ->start()
            ->clean()
            ->sse()
            ->write($publications)
            ->validate($this->request)
                ?->body()
            ->end();

        // Deinitializing rendered page
        unset($publications);

        // Exit (success)
        return null;
    }

    /**
     * Delete
     *
     * Delete the publication from the storage and the database
     *
     * @param int|string|null $identifier Identifier of the publication
     * @param int|bool $active Relevance if the publication
     * 
     * @return null
     */

    public function delete(int|string|null $identifier = null, int|bool $active = 0): null
    {
        // Initialized account and authorized to publications
        if ($this->account->access('publications')) {

            //Converting an identifier to Int
            $identifier = (int) $identifier;

            //Verification identifier
            if ($identifier > 0) {

                if (publication::delete($identifier, $active, $this->errors['publications'])) {
                    $status = true;
                    //Deleting publication

                } else {
                    $status = false;
                    //Not Deleting publication
                }
            } else {
                $status = false;
                //Data verification failed
            }
        }

        // Reading publications
        $this->view->publication = publication::read(expressions: ['account' => (int) $this->account->identifier], sort: '`created` DESC')[0] ?? null;

        // Redirecting 
        $publications = $this->view->render('publication.html');

        // Sending response
        $this->response
            ->start()
            ->clean()
            ->sse()
            ->write($publications)
            ->validate($this->request)
                ?->body()
            ->end();

        // Deinitializing rendered page
        unset($publications);

        // Exit (success)
        return null;
    }
}
