<?php

namespace App\Controller;

use App\Entity\Rank;
use App\Entity\User;
use App\Entity\Group;
use App\Entity\SubGroup;
use App\Form\AdminRankType;
use App\Form\AdminUserType;
use App\Form\SearchBarType;
use App\Form\AdminGroupType;
use App\Form\AdminSubGroupType;
use App\Repository\UserRepository;
use App\Repository\GroupRepository;
use Symfony\Component\Finder\Finder;
use App\Repository\DocumentRepository;
use App\Repository\DirectoryRepository;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Mime\FileinfoMimeTypeGuesser;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

#[Route('/admin', name: 'admin_')]
class AdminController extends AbstractController
{
    private Security $security;

    public function __construct(Security $security)
    {
        $this->security = $security;
    }

    #[Route('/', name: 'index')]
    public function index(
        DocumentRepository $DocumentRepository,
        UserRepository $UserRepository,
        DirectoryRepository $DirectoryRepository,
        GroupRepository $GroupRepository
    ): Response {
        return $this->render('admin/index.html.twig', [
            'controller_name' => 'AdminController',
            'documents' => $DocumentRepository->list()->order(['createdAt' => 'DESC'])->limit(5)->getResult(),
            'users' => $UserRepository->getAll()->order(['createdAt' => 'DESC'])->limit(5)->getResult(),
            'directories' => $DirectoryRepository->list()->order(['createdAt' => 'DESC'])->limit(5)->getResult(),
            'folders' => $DocumentRepository
                        ->list()
                        ->limitType("Folder")
                        ->order(['createdAt' => 'DESC'])
                        ->limit(5)
                        ->getResult(),
            'gangs' => $DocumentRepository
                        ->list()
                        ->limitType("Gang")
                        ->order(['createdAt' => 'DESC'])
                        ->limit(5)
                        ->getResult(),
            'groups' => $GroupRepository->getAll()->order(['createdAt' => 'DESC'])->limit(5)->getResult(),

        ]);
    }

    //-- users
    #[Route('/user', name: 'user_list')]
    public function user(PaginatorInterface $paginator, Request $request, UserRepository $UserRepository): Response
    {

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

        $pagination = $paginator->paginate(
            $UserRepository->getAll()
                ->search(
                    (
                                $searchForm->isSubmitted()
                                && $searchForm->isValid()
                                && $searchForm->getData()['subject'] !== null
                            ) ? $searchForm->getData()['subject'] : null,
                    true
                )
                ->getResult(),
            $request->query->getInt('page', 1)
        );

        return $this->render('admin/user.html.twig', [
            'controller_name' => 'AdminController',
            'searchForm' => $searchForm->createView(),
            'pagination' => $pagination,
        ]);
    }

    #[Route('/user/view/{id}', name: 'user_view')]
    public function userView(PaginatorInterface $paginator, User $User, Request $request): Response
    {
        $pagination = $paginator->paginate(
            $User->getDocuments(),
            $request->query->getInt('page', 1)
        );
        return $this->render('admin/user_view.html.twig', [
            'controller_name' => 'AdminController',
            'user' => $User,
            'pagination' => $pagination
        ]);
    }

    #[Route('/user/disable/{id}', name: 'user_disable')]
    public function userDisable(Request $Request, User $User): Response
    {
            $User->setIsDesactivated(($User->getIsDesactivated() ? false : true));
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($User);
        try {
            $entityManager->flush();
            if ($User->getIsDesactivated()) {
                $this->addFlash('success', 'alert_success_desactivating_user');
            } else {
                $this->addFlash('success', 'alert_success_activating_user');
            }
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_saving_user');
        }

        if (null != $Request->headers->get('referer')) {
            return $this->redirect($Request->headers->get('referer'));
        }
        return $this->redirectToRoute('admin_user_view', ['id' => $User->getId()]);
    }

    #[Route('/user/edit/{id}', name: 'user_edit')]
    public function userEdit(Request $request, User $User): Response
    {
        $currentUserGroup = $User->getMainGroup();
        $form = $this->createForm(AdminUserType::class, $User);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            if ($currentUserGroup != $User->getMainGroup()) {
                //if a user change group, he lost his SubGroups
                $User->getSubGroups()->clear();
            }

            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($User);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_saving_user');
                return $this->redirectToRoute('admin_user_edit', ['id' => $User->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_saving_user');
                return $this->redirectToRoute('admin_user_edit', ['id' => $User->getId()]);
            }
        }

        return $this->render('admin/user_edit.html.twig', [
            'controller_name' => 'AdminController',
            'user' => $User,
            'form' => $form->createView()
        ]);
    }

    //-- groups

    #[Route('/group', name: 'group_list')]
    public function group(PaginatorInterface $paginator, Request $request, GroupRepository $GroupRepository): Response
    {

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

        $pagination = $paginator->paginate(
            $GroupRepository->getAll()
                ->search(
                    (
                        $searchForm->isSubmitted()
                        && $searchForm->isValid()
                        && $searchForm->getData()['subject'] !== null
                    ) ? $searchForm->getData()['subject'] : null
                )->getResult(),
            $request->query->getInt('page', 1)
        );

        return $this->render('admin/group.html.twig', [
            'controller_name' => 'AdminController',
            'searchForm' => $searchForm->createView(),
            'pagination' => $pagination,
        ]);
    }

    #[Route('/group/view/{id}', name: 'group_view')]
    public function groupView(Group $Group): Response
    {
        return $this->render('admin/group_view.html.twig', [
            'controller_name' => 'AdminController',
            'group' => $Group,
        ]);
    }

    #[Route('/group/documents/{id}', name: 'group_documents')]
    public function groupDocuments(
        PaginatorInterface $paginator,
        Request $request,
        DocumentRepository $DocumentRepository,
        Group $Group
    ): Response {

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

        $pagination = $paginator->paginate(
            $DocumentRepository ->list()
                                ->limitGroup($Group)
                                ->search(
                                    (
                                        $searchForm->isSubmitted()
                                        && $searchForm->isValid()
                                        && $searchForm->getData()['subject'] !== null
                                    ) ? $searchForm->getData()['subject'] : null
                                )
                                ->order(['createdAt' => 'DESC'])
                                ->getResult(),
            $request->query->getInt('page', 1)
        );

        return $this->render('admin/group_documents.html.twig', [
            'controller_name' => 'AdminController',
            'pagination' => $pagination,
            'group' => $Group,
            'searchForm' => $searchForm->createView(),
        ]);
    }


    #[Route('/group/add', name: 'group_add')]
    public function groupAdd(Request $request): Response
    {
        $Group = new Group();
        $form = $this->createForm(AdminGroupType::class, $Group);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Group);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_creating_group');
                return $this->redirectToRoute('admin_group_view', ['id' => $Group->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_creating_group');
            }
        }

        return $this->render('admin/group_add.html.twig', [
            'controller_name' => 'AdminController',
            'group' => $Group,
            'form' => $form->createView()
        ]);
    }

    #[Route('/group/edit/{id}', name: 'group_edit')]
    public function groupEdit(Request $request, Group $Group): Response
    {
        $form = $this->createForm(AdminGroupType::class, $Group);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Group);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_editing_group');
                return $this->redirectToRoute('admin_group_view', ['id' => $Group->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_editing_group');
            }
        }

        return $this->render('admin/group_edit.html.twig', [
            'controller_name' => 'AdminController',
            'group' => $Group,
            'form' => $form->createView()
        ]);
    }

    #[Route('/group/delete/{id}', name: 'group_delete')]
    public function groupDelete(Group $Group): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->remove($Group);

        try {
            $entityManager->flush();
            $this->addFlash('success', 'alert_success_deleting_group');
            return $this->redirectToRoute('admin_group_list');
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_deleting_group');
            return $this->redirectToRoute('admin_group_view', ['id' => $Group->getId()]);
        }
    }

    //-- Groups Ranks

    #[Route('/group/rank/view/{id}', name: 'group_rank_view')]
    public function groupRankView(Rank $Rank): Response
    {
        return $this->render('admin/group_rank_view.html.twig', [
            'controller_name' => 'AdminController',
            'rank' => $Rank,
            'group' => $Rank->getMainGroup(),
        ]);
    }


    #[Route('/group/rank/edit/{id}', name: 'group_rank_edit')]
    public function groupRankEdit(Request $request, Rank $Rank): Response
    {

        $form = $this->createForm(AdminRankType::class, $Rank);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Rank);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_editing_rank');
                return $this->redirectToRoute('admin_group_rank_view', ['id' => $Rank->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_editing_rank');
            }
        }

        return $this->render('admin/group_rank_edit.html.twig', [
            'controller_name' => 'AdminController',
            'rank' => $Rank,
            'group' => $Rank->getMainGroup(),
            'form' => $form->createView()
        ]);
    }


    #[Route('/group/rank/add/{id}', name: 'group_rank_add')]
    public function groupRankAdd(Request $request, Group $Group): Response
    {
        $Rank = new Rank();
        $Rank->setMainGroup($Group);
        $form = $this->createForm(AdminRankType::class, $Rank);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($Rank);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_creating_rank');
                return $this->redirectToRoute('admin_group_rank_view', ['id' => $Rank->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_creating_rank');
            }
        }

        return $this->render('admin/group_rank_add.html.twig', [
            'controller_name' => 'AdminController',
            'rank' => $Rank,
            'group' => $Rank->getMainGroup(),
            'form' => $form->createView()
        ]);
    }

    #[Route('/rank/copy/{id}', name: 'group_rank_copy')]
    public function rankCopy(Rank $Rank): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $newrank = clone $Rank;
        $newrank->setName($newrank->getName() . ' - copy');
        $entityManager->persist($newrank);

        try {
            $entityManager->flush();
            $this->addFlash('success', 'alert_success_copying_rank');
            return $this->redirectToRoute('admin_group_rank_view', ['id' => $newrank->getId()]);
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_copying_rank');
            return $this->redirectToRoute('admin_group_rank_view', ['id' => $Rank->getId()]);
        }
    }

    #[Route('/rank/delete/{id}', name: 'group_rank_delete')]
    public function rankDelete(Rank $Rank): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->remove($Rank);

        try {
            $entityManager->flush();
            $this->addFlash('success', 'alert_success_deleting_rank');
            return $this->redirectToRoute('admin_group_view', ['id' => $Rank->getMainGroup()->getId()]);
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_deleting_rank');
            return $this->redirectToRoute('admin_group_rank_view', ['id' => $Rank->getId()]);
        }
    }

    //-- Groups SubGroups

    #[Route('/group/subgroup/view/{id}', name: 'group_subgroup_view')]
    public function groupSubGroupView(SubGroup $SubGroup): Response
    {
        return $this->render('admin/group_subgroup_view.html.twig', [
            'controller_name' => 'AdminController',
            'subgroup' => $SubGroup,
            'group' => $SubGroup->getMainGroup(),
        ]);
    }


    #[Route('/group/subgroup/edit/{id}', name: 'group_subgroup_edit')]
    public function groupSubGroupEdit(Request $request, SubGroup $SubGroup): Response
    {

        $form = $this->createForm(AdminSubGroupType::class, $SubGroup);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($SubGroup);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_editing_subgroup');
                return $this->redirectToRoute('admin_group_subgroup_view', ['id' => $SubGroup->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_editing_subgroup');
            }
        }

        return $this->render('admin/group_subgroup_edit.html.twig', [
            'controller_name' => 'AdminController',
            'subgroup' => $SubGroup,
            'group' => $SubGroup->getMainGroup(),
            'form' => $form->createView()
        ]);
    }


    #[Route('/group/subgroup/add/{id}', name: 'group_subgroup_add')]
    public function groupSubGroupAdd(Request $request, Group $Group): Response
    {
        $SubGroup = new SubGroup();
        $SubGroup->setMainGroup($Group);
        $form = $this->createForm(AdminSubGroupType::class, $SubGroup);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($SubGroup);
            try {
                $entityManager->flush();
                $this->addFlash('success', 'alert_success_creating_subgroup');
                return $this->redirectToRoute('admin_group_subgroup_view', ['id' => $SubGroup->getId()]);
            } catch (\Throwable $th) {
                if ($_ENV['APP_ENV'] === 'dev') {
                    throw $th; //DEBUG
                }
                $this->addFlash('danger', 'alert_error_creating_subgroup');
            }
        }

        return $this->render('admin/group_subgroup_add.html.twig', [
            'controller_name' => 'AdminController',
            'subgroup' => $SubGroup,
            'group' => $SubGroup->getMainGroup(),
            'form' => $form->createView()
        ]);
    }


    #[Route('/subgroup/delete/{id}', name: 'group_subgroup_delete')]
    public function subgroupDelete(SubGroup $SubGroup): Response
    {
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->remove($SubGroup);

        try {
            $entityManager->flush();
            $this->addFlash('success', 'alert_success_deleting_subgroup');
            return $this->redirectToRoute('admin_group_view', ['id' => $SubGroup->getMainGroup()->getId()]);
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_deleting_subgroup');
            return $this->redirectToRoute('admin_group_subgroup_view', ['id' => $SubGroup->getId()]);
        }
    }

    //-- Logs


    #[Route('/logs', name: 'logs')]
    public function logs(Request $Request): Response
    {
        $finder = new Finder();
        $finder->files()->in($this->getParameter('kernel.logs_dir'));

        return $this->render('admin/logs.html.twig', [
            'controller_name' => 'AdminController',
            'files' => $finder
        ]);
    }

    #[Route('/logs/view/{filename}', name: 'logs_view')]
    public function logsView(string $filename, Request $Request): Response
    {
            $filePath = $this->getParameter('kernel.logs_dir') . '/' . $filename;
            $filesystem = new Filesystem();

        if (!$filesystem->exists($filePath)) {
            throw new NotFoundHttpException('error_log_file_not_found');
        }


            $content = preg_replace(
                [
                    '/(?<=\[).+?(?=\])/'
                ],
                [
                    "<span class=\"text-success\">$0</span>"
                ],
                file_get_contents($filePath)
            );

            $content = str_replace(
                ['request.CRITICAL'],
                ["<span class=\"text-danger\">request.CRITICAL</span>"],
                $content
            );



        return $this->render('admin/logs_view.html.twig', [
            'controller_name' => 'AdminController',
            'name' => $filename,
            'path' => $filePath,
            'content' => $content
        ]);
    }

    #[Route('/logs/delete/{filename}', name: 'logs_delete')]
    public function logsDelete(string $filename, Request $Request): Response
    {
            $filePath = $this->getParameter('kernel.logs_dir') . '/' . $filename;
            $filesystem = new Filesystem();

        if (!$filesystem->exists($filePath)) {
            throw new NotFoundHttpException('error_log_file_not_found');
        }

        try {
            $filesystem->remove($filePath);
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_deleting_log');
            $referer = $Request->headers->get('referer');
            return $this->redirect($referer);
        }

            $this->addFlash('success', 'alert_success_deleting_log');
            return $this->redirectToRoute('admin_logs');
    }

    #[Route('/logs/download/{filename}', name: 'logs_download')]
    public function logsDownload(string $filename, Request $Request): Response
    {
            $filePath = $this->getParameter('kernel.logs_dir') . '/' . $filename;
            $filesystem = new Filesystem();

        if (!$filesystem->exists($filePath)) {
            throw new NotFoundHttpException('error_log_file_not_found');
        }

            // This should return the file to the browser as response
            $response = new BinaryFileResponse(
                $filePath
            );

            // To generate a file download, you need the mimetype of the file
            $mimeTypeGuesser = new FileinfoMimeTypeGuesser();

            // Set the mimetype with the guesser or manually
        if ($mimeTypeGuesser->isGuesserSupported()) {
            // Guess the mimetype of the file according to the extension of the file
            $response->headers->set(
                'Content-Type',
                $mimeTypeGuesser->guessMimeType(
                    $filePath
                )
            );
        } else {
            // Set the mimetype of the file manually, in this case for a text file is text/plain
            $response->headers->set('Content-Type', 'text/plain');
        }

            // Set content disposition inline of the file
            $response->setContentDisposition(
                ResponseHeaderBag::DISPOSITION_ATTACHMENT,
                $filename
            );

            return $response;
    }

    #[Route('/watchdog', name: 'watchdog')]
    public function watchdog(
        PaginatorInterface $paginator,
        Request $Request,
        EntityManagerInterface $EntityManagerInterface
    ): Response {
        /**
         * @var LogEntryRepository $logEntryRepository
         */
        $logEntryRepository = $EntityManagerInterface->getRepository('Gedmo\Loggable\Entity\LogEntry');

        $qb = $EntityManagerInterface->createQueryBuilder();

        $qb->select('l')
            ->from('Gedmo\Loggable\Entity\LogEntry', 'l')
            ->orderBy('l.loggedAt', 'DESC');

        $pagination = $paginator->paginate(
            $qb->getQuery()->getResult(),
            $Request->query->getInt('page', 1)
        );

        return $this->render('admin/watchdog.html.twig', [
            'controller_name' => 'AdminController',
            'pagination' => $pagination
        ]);
    }


    //-- Specials
    #[Route('/adminmode', name: 'mode')]
    public function adminMode(Request $Request): Response
    {
        /**
         * @var User $user
         * */
        $user = $this->security->getUser();

        $currentAdminMode = $user->getAdminmode();
        $newAdminMode = !(is_null($currentAdminMode) || $currentAdminMode);
        $user->setAdminmode($newAdminMode);

        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($user);

        try {
            $entityManager->flush();
        } catch (\Throwable $th) {
            if ($_ENV['APP_ENV'] === 'dev') {
                throw $th; //DEBUG
            }
            $this->addFlash('danger', 'alert_error_switching_adminmode');
        }


        $referer = $Request->headers->get('referer');
        return $this->redirect($referer);
    }
}
