<?php

namespace App\Controller\Blog;

use App\Core\Annotation\UrlGenerator;
use App\Core\Controller\Site\PageController;
use App\Core\Manager\EntityManager;
use App\Core\Site\SiteRequest;
use App\Core\Site\SiteStore;
use App\Entity\Blog\Category;
use App\Entity\Blog\Post;
use App\Factory\Blog\CommentFactory;
use App\Form\Blog\UserCommentType;
use App\Markdown\Parser\Post as PostParser;
use App\Repository\Blog\PostRepositoryQuery;
use App\UrlGenerator\PostGenerator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use App\Factory\Blog\PostFollowFactory;
use App\Manager\PostFollowManager;
use App\Core\Twig\Extension\EditorJsExtension;

class PostController extends PageController
{
    protected PostRepositoryQuery $postQuery;

    public function __construct(PostRepositoryQuery $postQuery, SiteRequest $siteRequest, SiteStore $siteStore)
    {
        parent::__construct($siteRequest, $siteStore);

        $this->postQuery = $postQuery;
    }

    /**
     * @UrlGenerator(service=PostGenerator::class, method="post")
     */
    public function post(
        Post $post,
        string $slug,
        CommentFactory $commentFactory,
        PostFollowManager $postFollowManager,
        Request $request,
        EntityManager $entityManager
    ): Response {
        if (Post::DRAFT === $post->getStatus() && !$this->getUser()) {
            throw $this->createNotFoundException();
        }

        if ($slug !== $post->getSlug()) {
            return $this->redirectToRoute(
                $this->siteRequest->getNode()->getRouteName(),
                [
                    'post' => $post->getId(),
                    'slug' => $post->getSlug(),
                ]
            );
        }

        $form = $this->createForm(UserCommentType::class, $commentFactory->create($post));

        if ($request->isMethod('POST')) {
            $form->handleRequest($request);

            if ($form->isValid()) {
                $data = $request->request->get($form->getName());
                $parentCommentId = (int) $data['parentCommentId'];
                $follow = (bool) ($data['follow'] ?? false);

                foreach ($post->getComments(['id' => $parentCommentId]) as $comment) {
                    $form->getData()->setParentComment($comment);
                }

                $entityManager->create($form->getData());

                $this->addFlash('success', 'Commentaire publié !');

                if ($follow && $form->getData()->getEmail()) {
                    $postFollowManager->create($post, $form->getData());
                }

                return $this->redirect($request->getUri());
            }

            $this->addFlash('error', 'Le formulaire n\'est pas valide.');
        }

        $similarPosts = $this->postQuery->getRepository()->findSimilarPosts($post, 3);

        return $this->defaultRender($this->siteRequest->getPage()->getTemplate(), [
            'post' => $post,
            'similarPosts' => $similarPosts,
            'form' => $form->createView(),
        ]);
    }

    public function posts(int $page = 1): Response
    {
        $entities = $this->createQuery()
            ->paginate($page, 5)
        ;

        return $this->defaultRender($this->siteRequest->getPage()->getTemplate(), [
            'pager' => $entities,
        ]);
    }

    public function search(Request $request, int $page = 1): Response
    {
        $query = $request->query->get('query');
        $tag = $request->query->get('tag');

        if ($query || $tag) {
            $entities = $this->createQuery()
                ->search($query, $tag)
                ->paginate($page, 5)
            ;
        }

        return $this->defaultRender($this->siteRequest->getPage()->getTemplate(), [
            'pager' => $entities ?? null,
            'query' => $query,
        ]);
    }

    /**
     * @UrlGenerator(service=PostGenerator::class, method="category")
     */
    public function category(Category $category, string $slug, int $page = 1): Response
    {
        $entities = $this->createQuery()
            ->inCategory($category, false)
            ->paginate($page, 5)
        ;

        if (!$category->getIsActive() && !$this->getUser()) {
            throw $this->createNotFoundException();
        }

        if ($slug !== $category->getSlug()) {
            return $this->redirectToRoute(
                $this->siteRequest->getNode()->getRouteName(),
                [
                    'category' => $category->getId(),
                    'slug' => $category->getSlug(),
                ]
            );
        }

        return $this->defaultRender($this->siteRequest->getPage()->getTemplate(), [
            'category' => $category,
            'pager' => $entities,
        ]);
    }

    public function tag(string $tag, int $page = 1): Response
    {
    }

    public function createQuery(): PostRepositoryQuery
    {
        return $this->postQuery->create()
            ->orderBy('.publishedAt', 'DESC')
            ->published()
        ;
    }

    public function rss(PostParser $parser, EditorJsExtension $editorJsExtension): Response
    {
        $entities = $this->createQuery()->paginate(1, 20);
        $items = [];

        foreach ($entities as $entity) {
            if ($entity->getContentFormat() === 'editorjs') {
                $description = $editorJsExtension->buildHtml($entity->getContent());
            } else {
                $description = $parser->transformMarkdown($entity->getContent());
            }

            $items[] = [
                'title' => $entity->getTitle(),
                'guid' => $entity->getId(),
                'date' => $entity->getPublishedAt(),
                'description' => $description,
                'categories' => call_user_func(function () use ($entity) {
                    foreach ($entity->getCategories() as $category) {
                        if ($category->getIsActive()) {
                            yield $category->getTitle();
                        }
                    }
                }),
                'link' => $this->generateUrl('blog_menu_post', [
                    'post' => $entity->getId(),
                    'slug' => $entity->getSlug(),
                ], UrlGeneratorInterface::ABSOLUTE_URL),
                'linkGemini' => sprintf('gemini://deblan.io/posts/%d.gmi', $entity->getId()),
            ];
        }

        $response = new Response();
        $response->headers->set('Content-Type', 'text/xml');

        return $this->defaultRender($this->siteRequest->getPage()->getTemplate(), [
            'items' => $items,
        ], $response);
    }

    public function jsonApi(PostParser $parser): Response
    {
        $entities = $this->createQuery()->paginate(1, 30);
        $items = [];

        foreach ($entities as $entity) {
            $items[] = [
                'id' => $entity->getId(),
                'title' => $entity->getTitle(),
                'date' => $entity->getPublishedAt()->format('Y-m-d H:i:s'),
                'link' => $this->generateUrl('blog_menu_post', [
                    'post' => $entity->getId(),
                    'slug' => $entity->getSlug(),
                ], UrlGeneratorInterface::ABSOLUTE_URL),
                'content' => $entity->getContent(),
                'categories' => call_user_func(function () use ($entity) {
                    foreach ($entity->getCategories() as $category) {
                        if ($category->getIsActive()) {
                            yield $category->getTitle();
                        }
                    }
                }),
            ];
        }

        return $this->json($items);
    }
}
