<?php

declare(strict_types=1);

namespace kodorvan\surikov\controllers;

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

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

/**
 * Books controller
 *
 * @package kodorvan\surikov\controllers
 *
 * @param array $errors Registry of errors
 *
 * @method null index() Books 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 books extends core
{
	/**
	 * Errors
	 *
	 * @var array $errors Registry of errors
	 */
	protected array $errors = [
		'system' => [],
		'account' => [],
		'books' => []
	];

	/**
	 * Books page (or the book page)
	 *
	 * @param int|string|null $identifier Identifier of the book
	 * @param int|string $page Page if the book
	 * @param int|string $next Next page if the book
	 * @return null
	 */
	public function index(
		int|string|null $identifier = null,
		int|string $page = 1,
		int|string $next = 0,
		int|string $last = 0
	): null {
		// Normalizing the page argument
		$page = (int) $page;
		if ($page < 1) {
			$page = 1;
		}

		if (isset($identifier)) {
			// Received the book identifier (the book)

			// Initializing the book
			$this->view->book = book::read(expressions: ['identifier' => (int) $identifier])[0] ?? null;

			if (!empty($page)) {
				// Received the book page 

				// Initializing the book page
				$this->view->page = $page;

				//Вынести в модель
				$next = $page + 1;
				$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier . DIRECTORY_SEPARATOR . $next . '.jpg';

				if (!file_exists($directory)) {
					$next = $page;
				}

				$last = $page - 1;

				$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier . DIRECTORY_SEPARATOR . $last . '.jpg';

				if (!file_exists($directory)) {
					$last = $page;
				}

				$this->view->next = $next;
				$this->view->last = $last;
			}

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

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

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

				// Deinitializing rendered page
				unset($page);

				// Exit (success)
				return null;
			}
		} else {
			// Not received the book identifier (all books)

			// Reading books
			$this->view->books = book::read(limit: 30, page: $page);

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

				// Render page
				$page = $this->view->render('books/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;
			}
		}

		// Exit (fail)
		return null;
	}

	/**
	 * Write
	 *
	 * Import books into the storage and the database
	 *
	 * @return null
	 */
	public function write(): null
	{
		if ($this->account->access('books')) {
			// Initialized account and authorized to books

			if (count($books = book::import(files: $this->request->files['books'] ?? [], errors: $this->errors['books'])) > 0) {
				$status = true;

				// Imported books
			} else {
				// Not imported books
			}
		}

		// Redirecting 
		header(header: 'Location: /books', response_code: status::see_other->value);

		// Exit (success)
		return null;
	}

	/**
	 * Read
	 *
	 * Read the book page file (expected jpeg image)
	 *
	 * @param int|string|null $identifier Identifier of the book
	 * @param int|string|null $page Page of the book
	 *
	 * @return string|null The book page file
	 */
	public function read(
		int|string|null $identifier = null,
		int|string|null $page = 1
	): ?string {
		// Normalizing the identifier argument
		$identifier = (int) $identifier;

		// Normalizing the page argument
		$page = (int) $page;
		if ($page < 1) {
			$page = 1;
		}

		// Initializing the publication file path
		$file = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier . DIRECTORY_SEPARATOR . $page . '.jpg';

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

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

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

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

		// Exit (fail)
		return null;
	}

	/**
	 * Delete
	 *
	 * Delete the book from the storage and the database
	 *
	 * @param int|string|null $identifier Identifier of the book
	 *
	 * @return null
	 */
	public function delete(int|string|null $identifier = null, int $active = 0): null
	{
		if (account::initialize(errors: $this->errors['account'])->access('books')) {
			// Initialized account and authorized to books

			// Initializing the processing status
			$status = false;

			// Normalizing the identifier argument
			$identifier = (int) $identifier;

			if (book::delete(identifier: $identifier, active: $active, errors: $this->errors['books'])) {
				// Deleted the book from the database

				// Initializing the book directory path
				$directory = \STORAGE . DIRECTORY_SEPARATOR . 'books' . DIRECTORY_SEPARATOR . $identifier;

				$status = true;
			}

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

				// Sending response
				$this->response
					->start()
					->clean()
					->sse()
					->json([
						'status' => $status,
						'errors' => $this->errors
					])
					->validate($this->request)
						?->body()
					->end();

				// Exit (success)
				return null;
			}
		}

		// Exit (fail)
		return null;
	}

	/**
	 * Rotate
	 *
	 * Rotate the book image in the storage
	 *
	 * @param int|string|null $identifier Identifier of the book
	 * @param int|string|null $page Page of the book
	 *
	 * @return null
	 */
	public function rotate(
		int|string|null $identifier = null,
		int|string|null $page = 1
	): null {
		if (account::initialize(errors: $this->errors['account'])->access('books')) {
			// Initialized account and authorized to books

			// Normalizing the identifier argument
			$identifier = (int) $identifier;

			// Normalizing the page argument
			$page = (int) $page;

			// Rotating the book page file
			$status = book::rotate(identifier: $identifier, page: $page, errors: $this->errors['books']);

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

				// Sending response
				$this->response
					->start()
					->clean()
					->sse()
					->json([
						'status' => $status,
						'errors' => $this->errors
					])
					->validate($this->request)
						?->body()
					->end();

				// Exit (success)
				return null;
			}
		}

		// Exit (fail)
		return null;
	}
}
