<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Controller\Admin;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer\ReviewModerationMailer;
use CpCreation\VitiCore\Marketing\Model\ProductReview;
use CpCreation\VitiCore\Marketing\Model\ProductReviewModerationAction;
use CpCreation\VitiCore\Marketing\Model\ProductReviewReport;
use CpCreation\VitiCore\Marketing\ProductReviewHistoryRecorder;
use CpCreation\VitiCore\Marketing\Repository\ProductReviewReportRepository;
use CpCreation\VitiCore\Marketing\Repository\ProductReviewRepository;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/marketing/signalements-avis')]
#[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_MARKETING')"))]
final class ProductReviewReportController extends AbstractController
{
    private const int PAGE_SIZE = 50;

    public function __construct(
        private readonly ProductReviewReportRepository $reportRepository,
        private readonly ProductReviewRepository $reviewRepository,
        private readonly ReviewModerationMailer $moderationMailer,
        private readonly ProductReviewHistoryRecorder $historyRecorder,
        private readonly PaginatorInterface $paginator,
        private readonly TranslatorInterface $translator,
    ) {}

    #[Route('', name: 'admin_marketing_product_review_reports', methods: ['GET'])]
    public function index(Request $request): Response
    {
        return $this->render('@CpCreationVitiCore/admin/marketing/product_review_report/index.html.twig', [
            'reports' => $this->paginator->paginate(
                $this->reportRepository->createAdminQueryBuilder(),
                max(1, $request->query->getInt('page', 1)),
                self::PAGE_SIZE,
            ),
            'moderation_reason_codes' => ProductReview::getAllowedModerationReasonCodes(),
        ]);
    }

    #[Route('/{id}/resoudre', name: 'admin_marketing_product_review_report_resolve', methods: ['POST'])]
    #[IsGranted('ROLE_SUPER_ADMIN')]
    public function resolve(Request $request, ProductReviewReport $report): RedirectResponse
    {
        if (!$this->hasValidCsrfToken($request, $report, 'resolve')) {
            return $this->invalidRequest();
        }
        if (!$this->isOpen($report)) {
            return $this->alreadyProcessed();
        }

        $note = $this->resolveNote($request);
        $report->resolve($note);
        $this->historyRecorder->record(
            review: $report->getReview(),
            action: ProductReviewModerationAction::ACTION_REPORT_RESOLVED,
            reasonCode: $report->getReason(),
            reasonDetail: $note,
        );
        $this->reportRepository->save($report);
        $this->addFlash('alert-success', $this->translator->trans('marketing.review_report.admin.resolved'));

        return $this->redirectToRoute('admin_marketing_product_review_reports');
    }

    #[Route('/{id}/classer', name: 'admin_marketing_product_review_report_dismiss', methods: ['POST'])]
    #[IsGranted('ROLE_SUPER_ADMIN')]
    public function dismiss(Request $request, ProductReviewReport $report): RedirectResponse
    {
        if (!$this->hasValidCsrfToken($request, $report, 'dismiss')) {
            return $this->invalidRequest();
        }
        if (!$this->isOpen($report)) {
            return $this->alreadyProcessed();
        }

        $note = $this->resolveNote($request);
        $report->dismiss($note);
        $this->historyRecorder->record(
            review: $report->getReview(),
            action: ProductReviewModerationAction::ACTION_REPORT_DISMISSED,
            reasonCode: $report->getReason(),
            reasonDetail: $note,
        );
        $this->reportRepository->save($report);
        $this->addFlash('alert-success', $this->translator->trans('marketing.review_report.admin.dismissed'));

        return $this->redirectToRoute('admin_marketing_product_review_reports');
    }

    #[Route('/{id}/retirer-avis', name: 'admin_marketing_product_review_report_withdraw', methods: ['POST'])]
    #[IsGranted('ROLE_SUPER_ADMIN')]
    public function withdrawReview(Request $request, ProductReviewReport $report): RedirectResponse
    {
        if (!$this->hasValidCsrfToken($request, $report, 'withdraw')) {
            return $this->invalidRequest();
        }
        if (!$this->isOpen($report)) {
            return $this->alreadyProcessed();
        }

        $reasonCode = (string) $request->request->get('reason_code');
        if (!\in_array($reasonCode, ProductReview::getAllowedModerationReasonCodes(), true)) {
            $this->addFlash('alert-danger', $this->translator->trans('marketing.review_report.admin.withdrawal_reason_required'));

            return $this->redirectToRoute('admin_marketing_product_review_reports');
        }

        $review = $report->getReview();
        if (ProductReview::STATUS_PUBLISHED !== $review->getStatus()) {
            $this->addFlash('alert-danger', $this->translator->trans('marketing.review_report.admin.withdrawal_unavailable'));

            return $this->redirectToRoute('admin_marketing_product_review_reports');
        }

        $reasonDetail = $this->resolveNote($request);
        $now = new \DateTimeImmutable();
        $review->withdraw($reasonCode, $reasonDetail, $now);
        $report->resolve($reasonDetail, $now);
        $this->historyRecorder->record(
            review: $review,
            action: ProductReviewModerationAction::ACTION_WITHDRAWN,
            reasonCode: $reasonCode,
            reasonDetail: $reasonDetail,
            occurredAt: $now,
        );
        $this->reviewRepository->persist($review);
        $this->reportRepository->persist($report);
        $this->reportRepository->flush();
        $this->moderationMailer->sendWithdrawal($review);
        $this->addFlash('alert-success', $this->translator->trans('marketing.review_report.admin.review_withdrawn'));

        return $this->redirectToRoute('admin_marketing_product_review_reports');
    }

    private function hasValidCsrfToken(Request $request, ProductReviewReport $report, string $action): bool
    {
        return $this->isCsrfTokenValid(
            $action . '-review-report-' . $report->getId()->toString(),
            (string) $request->request->get('_token'),
        );
    }

    private function invalidRequest(): RedirectResponse
    {
        $this->addFlash('alert-danger', $this->translator->trans('marketing.review_report.admin.invalid_request'));

        return $this->redirectToRoute('admin_marketing_product_review_reports');
    }

    private function alreadyProcessed(): RedirectResponse
    {
        $this->addFlash('alert-info', $this->translator->trans('marketing.review_report.admin.already_processed'));

        return $this->redirectToRoute('admin_marketing_product_review_reports');
    }

    private function isOpen(ProductReviewReport $report): bool
    {
        return ProductReviewReport::STATUS_OPEN === $report->getStatus();
    }

    private function resolveNote(Request $request): ?string
    {
        $note = mb_trim((string) $request->request->get('note'));

        return '' === $note ? null : mb_substr($note, 0, 2000);
    }
}
