<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\File;
use App\Models\Story;
use App\Services\Session;
use App\Services\Validator;
use Intervention\Image\Constraint;
use Intervention\Image\ImageManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

/**
 * UploadController
 */
class UploadController extends Controller
{
    public function __construct(
        protected Session $session,
        protected Validator $validator,
        protected ImageManager $imageManager,
    ) {}

    /**
     * Upload file
     *
     * @param Request  $request
     * @param Response $response
     *
     * @return Response
     */
    public function upload(Request $request, Response $response): Response
    {
        $user  = getUser();
        $input = (array) $request->getParsedBody();
        $files = $request->getUploadedFiles();
        $input = array_merge($input, $files);

        $id = $input['id'] ?? 0;

        if ($id) {
            $model = Story::query()->find($id);

            if (! $model) {
                return $this->json($response, [
                    'success' => false,
                    'message' => 'Запись не найдена!',
                ]);
            }

            $this->validator->custom(
                $model->user_id === $user->id || isAdmin(),
                'Вы не являетесь автором данной записи!'
            );
        } else {
            $model = new Story();
        }

        $this->validator
            ->required(['csrf', 'file'])
            ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!')
            ->file('file', [
                'size_max'   => setting('file.size_max'),
                'extensions' => setting('file.extensions'),
                'weight_max' => setting('image.weight_max'),
                'weight_min' => setting('image.weight_min'),
            ]);

        $countFiles = File::query()
            ->where('user_id', getUser('id'))
            ->where('story_id', $id)
            ->count();

        $this->validator->custom(
            $countFiles < setting('file.total_max'),
            sprintf('Разрешено загружать не более %d файлов!', setting('file.total_max'))
        );

        if ($this->validator->isValid($input)) {
            $file      = $input['file'];
            $filename  = sanitize($file->getClientFilename());
            $extension = getExtension($filename);
            $path      = $model->uploadPath . '/' . uniqueName($extension);

            if (in_array($extension, File::IMAGES, true)) {
                $img = $this->imageManager->make($file->getFilePath());
                $img->resize(setting('image.resize'), setting('image.resize'), static function (Constraint $constraint) {
                    $constraint->aspectRatio();
                    $constraint->upsize();
                });

                $img->save(publicPath($path));
            } else {
                $file->moveTo(publicPath($path));
            }

            $file = File::query()->create([
                'user_id'    => $user->id,
                'story_id'   => $id,
                'path'       => $path,
                'name'       => $filename,
                'ext'        => $extension,
                'size'       => $file->getSize(),
                'created_at' => time(),
            ]);

            return $this->json($response, [
                'success' => true,
                'id'      => $file->id,
                'path'    => $file->path,
                'name'    => $file->name,
                'size'    => formatSize($file->size),
                'type'    => $file->isImage() ? 'image' : 'file',
            ]);
        }

        return $this->json($response, [
            'success' => false,
            'message' => current($this->validator->getErrors()),
        ]);
    }

    /**
     * Delete file
     *
     * @param int      $id
     * @param Request  $request
     * @param Response $response
     *
     * @return Response
     */
    public function destroy(int $id, Request $request, Response $response): Response
    {
        $user  = getUser();
        $input = (array) $request->getParsedBody();

        $file = File::query()->find($id);

        if (! $file) {
            return $this->json($response, [
                'success'  => false,
                'message'  => 'Файл не найден!'
            ]);
        }

        $this->validator
            ->required(['csrf'])
            ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!')
            ->custom($file->user_id === $user->id || isAdmin(), 'Вы не являетесь автором данного файла!');

        if ($this->validator->isValid($input)) {
            $file->delete();

            return $this->json($response, [
                'success' => true,
                'path'    => $file->path,
            ]);
        }

        return $this->json($response, [
            'success' => false,
            'message' => current($this->validator->getErrors()),
        ]);
    }
}
