<?php

namespace App\Controller;

use App\Entity\Directory;
use App\Form\DirectoryType;
use App\Form\SearchBarType;
use Psr\Log\LoggerInterface;
use App\Repository\DocumentRepository;
use App\Repository\DirectoryRepository;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\CertificateRepository;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

#[Route('/directory', name: 'directory_')]
class DirectoryController extends AbstractController
{
    private LoggerInterface $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }


    #[Route('/', name: 'list')]
    #[Route('/wanted', name: 'list_wanted')]
    #[Route('/dead', name: 'list_dead')]
    public function list(
        PaginatorInterface $paginator,
        Request $request,
        DirectoryRepository $DirectoryRepository
    ): Response {



        $searchForm = $this->createForm(SearchBarType::class);
        $searchForm->handleRequest($request);

        $req = $DirectoryRepository
                        ->list()
                        ->order(['createdAt' => 'DESC'])
                        ->search(
                            (
                                $searchForm->isSubmitted()
                                && $searchForm->isValid()
                                && $searchForm->getData()['subject'] !== null
                            ) ? $searchForm->getData()['subject'] : null
                        );

        if ($request->attributes->get('_route') == 'directory_list_wanted') {
            $req->wanted();
        }

        if ($request->attributes->get('_route') == 'directory_list_dead') {
            $req->dead();
        } else {
            $req->notDead();
        }

        $pagination = $paginator->paginate(
            $req->getResult(),
            $request->query->getInt('page', 1)
        );

        return $this->render('directory/list.html.twig', [
            'controller_name' => 'DirectoryController',
            'pagination' => $pagination,
            'searchForm' => $searchForm->createView(),
            'wanted' => ($request->attributes->get('_route') == 'directory_list_wanted'),
            'dead' => ($request->attributes->get('_route') == 'directory_list_dead')
        ]);
    }

    #[Route('/view/{id}', name: 'view')]
    public function view(Directory $Directory): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $DocumentList = [
            'Certificate',
            'Complaint',
            'Licencewithdrawal',
            'Infringement',
            'Jail',
            'Bracelet',
            'Criminal',
            'Stolenvehicle',
            'Medical'
        ];
        $RenderArray = [
            'controller_name' => 'DirectoryController',
            'directory' => $Directory,
        ];
        foreach ($DocumentList as $key => $dType) {
            /**
             * Use Certificate as example for IDE
             * @var CertificateRepository $repo
             */
            $repo =  $entityManager->getRepository('App\Entity\\' . $dType);
            $RenderArray[$dType] = $repo->listForUser($this->getUser())
                                        ->limitDirectory($Directory)
                                        ->order(['createdAt' => 'DESC'])
                                        ->limit(4)
                                        ->getResult();
        }


        return $this->render('directory/view.html.twig', $RenderArray);
    }


    #[Route('/create', name: 'create')]
    public function create(Request $request): Response
    {
        $Directory = new Directory();
        if (!$this->IsGranted('create', $Directory)) {
            throw new AccessDeniedHttpException('granted_not_allowed_creating_directory');
        }

        $form = $this->createForm(DirectoryType::class, $Directory);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Directory);
            try {
                $entityManager->flush();
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                } else {
                    $this->logger->error($th);
                }

                $this->addFlash('danger', 'alert_error_creating_directory');
                return $this->redirectToRoute($request->getRequestUri());
            }

            $this->addFlash('success', 'alert_success_creating_directory');
            return $this->redirectToRoute('directory_view', ['id' => $Directory->getId()]);
        } elseif ($form->isSubmitted() && !$form->isValid()) {
            $this->addFlash('warning', 'alert_error_form_post');
        }

        return $this->render('directory/create.html.twig', [
            'controller_name' => 'DirectoryController',
            'directory' => $Directory,
            'form' => $form->createView()
        ]);
    }

    #[Route('/edit/{id}', name: 'edit')]
    #[IsGranted('edit', subject: 'Directory', message: 'granted_not_allowed_editing_directory')]
    public function edit(Request $request, Directory $Directory): Response
    {
        $form = $this->createForm(DirectoryType::class, $Directory);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Directory);
            try {
                $entityManager->flush();
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                } else {
                    $this->logger->error($th);
                }

                $this->addFlash('danger', 'alert_error_editing_directory');
                return $this->redirectToRoute($request->getRequestUri());
            }

            $this->addFlash('success', 'alert_success_editing_directory');
            return $this->redirectToRoute('directory_view', ['id' => $Directory->getId()]);
        } elseif ($form->isSubmitted() && !$form->isValid()) {
            $this->addFlash('warning', 'alert_error_form_post');
        }

        return $this->render('directory/edit.html.twig', [
            'controller_name' => 'DirectoryController',
            'directory' => $Directory,
            'form' => $form->createView()
        ]);
    }

    #[Route('/delete/{id}', name: 'delete')]
    #[IsGranted('delete', subject: 'Directory', message: 'granted_not_allowed_deleting_directory')]
    public function delete(Directory $Directory): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->remove($Directory);
        try {
            $entityManager->flush();
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('warning', 'alert_error_deleting_directory');
            return $this->redirectToRoute('directory_view', ['id' => $Directory->getId()]);
        }

        $this->addFlash('success', 'alert_success_deleting_directory');
        return $this->redirectToRoute('directory_list');
    }

    #[Route('/merge/router', name: 'merge_router')]
    public function directoryMergeRouter(Request $Request): Response
    {
        if (empty($Request->request->get('directory-main')) || is_null($Request->request->get('directory-main'))) {
            return $this->redirectToRoute('directory_list'); //id not found = redirect to list
        }
        if (empty($Request->request->get('directory-child')) || is_null($Request->request->get('directory-child'))) {
            return $this->redirectToRoute('directory_list'); //id not found = redirect to list
        }

        return $this->redirectToRoute(
            'directory_merge',
            [
                'keeped' => $Request->request->get('directory-main'),
                'deleted' => $Request->request->get('directory-child')
            ]
        );
    }


    #[Route('/merge/{deleted}/{keeped}', name: 'merge')]
    #[IsGranted('delete', subject: 'keeped', message: 'granted_not_allowed_merging_directory')]
    public function merge(
        Directory $deleted,
        Directory $keeped,
        Request $Request,
        EntityManagerInterface $EntityManagerInterface
    ): Response {

        $base = clone $keeped;

        // 1 : merge info before validation for display
        $classMetadata = $EntityManagerInterface->getClassMetadata(Directory::class);
        foreach ($classMetadata->getFieldNames() as $key => $f) {
            if (
                is_null($classMetadata->getFieldValue($keeped, $f))
                && !is_null($classMetadata->getFieldValue($deleted, $f))
            ) {
                $classMetadata->setFieldValue($keeped, $f, $classMetadata->getFieldValue($deleted, $f));
            }
        }

        if (null != ($Request->request->get('validatemerge')) && !empty($Request->request->get('validatemerge'))) {
            //after validation

            // 2 : check foreing keys
            $entityManager = $this->getDoctrine()->getManager();
            foreach ($classMetadata->getAssociationMappings() as $key => $associationMapping) {
                    //get mappings of deleted entity
                    $mappings = $classMetadata->getFieldValue($deleted, $associationMapping['fieldName']);

                if (is_a($mappings, 'Doctrine\ORM\PersistentCollection')) {
                    //if mapping is a Collection
                    foreach ($mappings as $mapping) {
                        if (is_object($mapping) && method_exists($mapping, 'setDirectory')) {
                            $mapping->setDirectory($keeped);
                        }
                    }
                } else {
                    $entityManager->initializeObject($mappings);
                    if (is_object($mappings) && method_exists($mappings, 'addDirectory')) {
                        $mappings->addDirectory($keeped);
                    }
                }
            }


            $entityManager->persist($keeped);
            try {
                $entityManager->flush();
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                } else {
                    $this->logger->error($th);
                }
                $this->addFlash('danger', 'alert_error_merging_directory');
                return $this->redirectToRoute('directory_view', ['id' => $deleted->getId()]);
            }

            $entityManager->refresh($deleted); //refresh entity after flushing, to avoid deleting mappings
            $deletedId = $deleted->getId();
            $entityManager->remove($deleted);

            //dd($deleted);

            try {
                $entityManager->flush();
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                } else {
                    $this->logger->error($th);
                }
                $this->addFlash('danger', 'alert_error_merging_directory');
                return $this->redirectToRoute('directory_view', ['id' => $deletedId]);
            }

            $this->addFlash('success', 'alert_success_merging_directory');
            return $this->redirectToRoute('directory_view', ['id' => $keeped->getId()]);
        }

        return $this->render('directory/merge.html.twig', [
            'controller_name' => 'DirectoryController',
            'baseDirectory' => $base,
            'keepedDirectory' => $keeped,
            'deletedDirectory' => $deleted
        ]);
    }


    #[Route('/history/{id}', name: 'history')]
    public function history(Directory $Directory, EntityManagerInterface $em): Response
    {

        /**
         * @var LogEntryRepository $logEntryRepository
         */
        $logEntryRepository = $em->getRepository('Gedmo\Loggable\Entity\LogEntry');
        $directoryHistory = $logEntryRepository->getLogEntries($Directory);
        return $this->render('directory/history.html.twig', [
            'controller_name' => 'DocumentController',
            'directory' => $Directory,
            'history' => $directoryHistory,
        ]);
    }
}
