<?php

namespace AutoAdmin\Bundle\Media\Admin\Controller;

use AutoAdmin\Bundle\Admin\Controller\Admin\AbstractAdminController;
use AutoAdmin\Bundle\Admin\Factory\ContentFactory;
use AutoAdmin\Bundle\Core\Util\SizeConverter;
use AutoAdmin\Bundle\Media\Form\Type\Media\MediaApiType;
use AutoAdmin\Bundle\Media\Library\MediaFileValidator;
use AutoAdmin\Bundle\Media\Library\MediaLibrary;
use AutoAdmin\Bundle\Media\Library\MediaTypeResolver;
use AutoAdmin\Bundle\Media\Library\PreviewGenerator;
use AutoAdmin\Bundle\Media\Model\Library\FileMediaInterface;
use AutoAdmin\Bundle\Media\Upload\MediaUploadHandler;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;


#[Route('/admin/{_admin_locale}/library', name: 'aa_admin_media_library_')]
class LibraryAdminController extends AbstractAdminController
{
    public function __construct(
        protected MediaTypeResolver $typeResolver,
        protected MediaLibrary $library,
        protected PreviewGenerator $previewGenerator,
        protected SerializerInterface $baseSerializer,
        protected MediaUploadHandler $uploadHandler,
        protected ContentFactory $contentFactory,
        protected SizeConverter $sizeConverter,
        protected MediaFileValidator $mediaFileValidator,
        protected string $projectDir,
    ) {
    }

    #[Route('/', name: 'endpoint')]
    public function endpoint(Request $request)
    {
        // only used for generating endpoint url
    }

    #[Route('/browse', name: 'browse')]
    public function browse(Request $request)
    {
        $typeSlugs = explode(',', $request->query->get('mediaTypes'));
        $searchTerm = $request->query->get('searchTerm');
        $page = max(intval($request->query->get('page', 1)), 1);

        $results = $this->library->browse($typeSlugs, $page, $searchTerm);
        $count = $this->library->browseCount($typeSlugs, $page, $searchTerm);

        $jsonArray = [
            'items' => $results,
            'page' => $page,
            'maxPage' => ceil($count / MediaLibrary::PER_PAGE),
            'count' => $count,
            'maxUploadSize' => $this->sizeConverter->getMinUploadSizeAsBytes(),
            'maxUploadSizeReadable' => $this->sizeConverter->getMinUploadSizeReadable(),
            'mediaTypesConfig' => $this->typeResolver->getSerializableConfig($typeSlugs),
        ];
        $jsonResults = $this->baseSerializer->serialize($jsonArray, 'json', [
            'groups' => [
                'id',
                'dates',
                'media',
//                'translation',// translation handled by dedicated normalizer
            ],
        ]);

        return new JsonResponse($jsonResults, 200, [], true);
    }

    #[Route('/upload', name: 'upload')]
    public function upload(Request $request)
    {
        $mainStatus = true;
        $errors = [];
        $successes = [];
        $models = [];
        $filenames = [];

        $form = $this->createForm(MediaApiType::class, null, ['csrf_protection' => false]);
        $form->submit($request->request->all());

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $data = $form->getData();
            $type = $data['media_upload_type'];
            $files = $request->files->all();
            $files = $files['media_upload_file'];
            $class = $this->typeResolver->getTypeClass($type);

            /** @var UploadedFile $file */
            foreach ($files as $file) {
                list($isValid, $validationErrors) = $this->mediaFileValidator->validate($type, $file);
                if (!$isValid) {
                    $errors[$file->getClientOriginalName()] = $validationErrors;
                    $mainStatus = false;
                    continue;
                }
                $model = $this->contentFactory->createEntity($class);
                if ($model instanceof FileMediaInterface) {
                    $model->setFile($file);
                }

                $status = $this->uploadHandler->handle($model);
                if (!$status) {
                    $mainStatus = false;
                    if (!array_key_exists($file->getFilename(), $errors)) {
                        $errors[$file->getFilename()] = [];
                    }
                    $errors[$file->getFilename()][] = 'Erreur lors de l\'upload.';
                }

                $models[] = $model;
            }

            foreach ($models as $model) {
                if ($filename = $model?->getCurrentTranslation()?->getFileName()) {
                    $filenames[] = $filename;
                }
                $this->em->persist($model);
            }
            $this->em->flush();

            if (empty($errors)) {
                $successes[] = 'Upload terminé avec succès.';
            } elseif (!empty($filenames)) {
                // partial success, group successes under one message to simplify output
                $successes[] = 'Upload OK ('.implode(',', $filenames).').';
            }
        } else {
            $errs = $form->getErrors(true, true);
            foreach ($errs as $err) {
                $errors[] = $err->getMessage();
            }
        }

        return new JsonResponse([
            'indexedErrors' => $errors,
            'errors' => array_values($errors),
            'successes' => $successes,
            'status' => $mainStatus,
            'files' => $filenames,
        ]);
    }

    #[Route('/delete/{type}/{id}', name: 'delete')]
    public function delete(Request $request)
    {
        $type = $request->get('type');
        $id = $request->get('id');

        $status = false;
        $json = [];
        $media = $this->library->get($type, $id);
        if ($media) {
            $this->em->remove($media);
            $this->em->flush();
            $status = true;
            $json['successes'] = [];
            $json['successes'][] = 'Suppression effectuée avec succès.';
        }

        return new JsonResponse([
            'status' => $status,
            ...$json,
        ]);
    }

    #[Route('/form/preview/{type}/{id}', name: 'form_preview')]
    public function refreshPreview(Request $request)
    {
        $type = $request->get('type');
        $id = $request->get('id');

        return new JsonResponse([
            'status' => true,
            'preview' => $this->previewGenerator->getPreview($type, $id),
        ]);
    }

    #[Route('/serve/{site_slug}/{type_slug}/{file_path}', name: 'serve')]
    public function serveMedia(Request $request): BinaryFileResponse
    {
        $typeSlug = $request->get('type_slug');
        $mappingCfg = $this->typeResolver->getTypeConfig($typeSlug);

        $replace = [
            //'path' => '/var/aa_media/{site_slug}/{type_slug}/{filename}',
            '{site_slug}' => $request->get('site_slug'),
            '{type_slug}' => $request->get('type_slug'),
            '{filename}' => $request->get('file_path'),
        ];

        $mappingPath = $mappingCfg['path'];
        $mappingPath = str_replace(array_keys($replace), array_values($replace), $mappingPath);
        $filepath = $this->projectDir.$mappingPath;

        return $this->file($filepath, null, ResponseHeaderBag::DISPOSITION_INLINE);
    }
}
