<?php

namespace AppBundle\Controller;

use AppBundle\Entity\DepotDocument;
use AppBundle\Entity\DocumentDisposition;
use AppBundle\Entity\Historique;
use AppBundle\Entity\Interlocuteur;
use AppBundle\Entity\TelechargementDocumentDisposition;
use AppBundle\Entity\Utilisateur;
use AppBundle\Form\Document\DepotDocumentType;
use DateTime;
use Exception;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\FileBag;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

/**
 * Class DocumentDispositionController
 * @package AppBundle\Controller
 * @Route("/documents")
 */
class DocumentController extends Controller {

    /**
     * @Route("/disposition", name="documentDispo")
     * @Template("@App/DocumentDisposition/list.html.twig")
     */
    public function aDispositionAction() {
        $em = $this->getDoctrine()->getManager();
        $user = $this->getUser();
        $doc = $this->getDoctrine();

        $entete = $doc->getManager()->getRepository('AppBundle:Entete')->findOneBy(['localisation' => 'DocumentDisposition']);

        $docs = $em->getRepository('AppBundle:DocumentDisposition')->getDocumentsSQL($user);

        return [
            'documents' => $docs,
            'entete' => $entete
        ];
    }

    /**
     * @Route("/depot", name="documentDepo")
     * @Template("@App/Document/depo.html.twig")
     */
    public function depoAction(Request $request) {
        $doc = $this->getDoctrine();
        /** @var Utilisateur $user */
        $user = $this->getUser();
        $agence = $doc->getRepository('AppBundle:Agence')->findAll()[0];
        $entete = $doc->getManager()->getRepository('AppBundle:Entete')->findOneBy(['localisation' => 'Depots']);

        $docs = [];
        /** @var Interlocuteur $interloc */
        foreach ($user->getInterlocuteurSiret() as $interloc) {
            foreach ($interloc->getDepoDocuments() as $document) {
                $docs[] = $document;
            }
        }

        $thems = $user->getThematique();
        $interloc = $user->getInterlocuteurSiret();

        $form = $this->createForm(DepotDocumentType::class);

        return [
            'form' => $form->createView(),
            'agence' => $agence,
            'thems' => $thems,
            'interloc' => $interloc,
            'documents' => $docs,
            'entete' => $entete
        ];
    }

    /**
     * @param Request $request
     * @Route("/depot/uploadDoc", name="documentDepoUpload")
     * @Method("POST")
     * @return JsonResponse
     */
    public function ajaxUploadDocDepoAction(Request $request) {
        $doc = $this->getDoctrine();
        $em = $doc->getManager();
        $user = $this->getUser();

        /** @var UploadedFile $file */
        $file = $request->files->all()['file'];
        $nom = $file->getClientOriginalName();
        $ext = $file->getClientOriginalExtension();

        $time = new DateTime();
        $time = $time->format('ymdHis');

        $thematique = $this->get('session')->get('thematique');
        $siret = $this->get('session')->get('siret');
        $this->get('session')->remove('thematique');
        $this->get('session')->remove('siret');

        if ($thematique == null || $siret == null) {
            return new JsonResponse('La thématique n\'a pas été reconnue', 500);
        }

        $objThematique = $doc->getRepository("AppBundle:Thematique")->find($thematique);
        $objInterlocuteur = $doc->getRepository("AppBundle:Interlocuteur")->find($siret);


        $batchCheckMntFolders = $this->getParameter('batchCheckFolders');
        $dirCheckMntFolders = $this->getParameter('dirCheckFolders');
        $folderCheckOutput = shell_exec("sh $dirCheckMntFolders$batchCheckMntFolders  2>&1");
        if (strpos(strtolower($folderCheckOutput), 'failure')) {
            $this->sendErrorFileUploadToAdmin($folderCheckOutput);
            return new JsonResponse(utf8_decode("Anomalie technique sur la fonction de dépôt ; veuillez ré-essayer ultérieurement"), 500);
        }
        if ($thematique == "RRPC") {

            $repertoireDestination = $this->getParameter('dirTmpRRPC');
            $dirBatchRRPC = $this->getParameter('dirBatchRRPC');
            $batchRRPC = $this->getParameter('batchRRPC');
            $prefixeRRPC = $this->getParameter('prefixeRRPC');

            $nomDestination = $prefixeRRPC . '_' . $siret . '_' . $time . '.' . $ext;
            $emplacement = $repertoireDestination . $nomDestination;

            try {

                if (!file_exists($repertoireDestination)) {
                    throw new Exception("Fichier non déplacé");
                }

                $wres = move_uploaded_file($file, $emplacement);

                if (!$wres) {
                    //ob_start();
                    //var_dump($wres);
                    //$wcontent = ob_get_contents();
                    //ob_end_clean();

                    throw new Exception("RRPC move_uploaded_file pbl avec le fichier=" . $emplacement);
                }



                $output = shell_exec("sh $dirBatchRRPC/$batchRRPC --context_param nomFichier=" . Basename($repertoireDestination . $nomDestination, '.' . $ext) . " 2>&1");

                if (strpos(strtolower($output), 'erreur') == false && strpos(strtolower($output), "is not recognized as an internal or external command") == false) {

                    $histo = new Historique('Dépot', 'Document', $user->getUsername() . ' a déposé le document ' . $nom, $user);

                    $doc = new DepotDocument($nom, $emplacement, $objThematique, $objInterlocuteur, $this->getUser());
                    $em->persist($doc);
                    $em->persist($histo);

                    try {
                        $em->flush();
                    } catch (Exception $e) {
                        $this->sendErrorFileUploadToAdmin($e->getMessage());
                        return new JsonResponse($e->getMessage(), 500);
                    }
                    return new JsonResponse(utf8_decode('Votre fichier est conforme au format attendu : il est accepté'));
                } else {
                    $this->sendErrorFileUploadToAdmin('Votre fichier ne reste pas le format attendu');
                    return new JsonResponse(utf8_decode('Votre fichier ne reste pas le format attendu'), 500);
                }
            } catch (Exception $e) {
                // si echec du move
                $this->sendErrorFileUploadToAdmin($e->getMessage());
                return new JsonResponse($e->getMessage(), 500);
            }
        } elseif ($thematique == "ANC") {

            $repertoireDestination = $this->getParameter('dirTmpANC');
            $batchANC = $this->getParameter('batchANC');
            $prefixeANC = $this->getParameter('prefixeANC');

            $nomDestination = $prefixeANC . '_' . $siret . '_' . $time . '.' . $ext;
            $emplacement = $repertoireDestination . $nomDestination;

            try {

                if (!file_exists($repertoireDestination)) {
                    throw new Exception("Fichier non déplacé");
                }

                move_uploaded_file($file, $emplacement);

                $output = shell_exec("sh ./$batchANC --context_param nomFichier=" . Basename($repertoireDestination . $nomDestination, '.' . $ext) . " 2>&1");

                if (strpos(strtolower($output), 'erreur') == false && strpos(strtolower($output), "is not recognized as an internal or external command") == false) {
                    $histo = new Historique('Dépot', 'Document', $user->getUsername() . ' a déposé le document ' . $nom, $user);

                    $doc = new DepotDocument($nom, $emplacement, $objThematique, $objInterlocuteur, $this->getUser());
                    $em->persist($doc);
                    $em->persist($histo);

                    try {
                        $em->flush();
                    } catch (Exception $e) {
                        $this->sendErrorFileUploadToAdmin($e->getMessage());
                        return new JsonResponse($e->getMessage(), 500);
                    }
                    return new JsonResponse(utf8_decode($output));
                } else {
                    $this->sendErrorFileUploadToAdmin($output);
                    return new JsonResponse(utf8_decode($output), 500);
                }
            } catch (Exception $e) {
                // si echec du move
                $this->sendErrorFileUploadToAdmin($e->getMessage());
                return new JsonResponse($e->getMessage(), 500);
            }
        } elseif ($thematique == "APE") {

            $repertoireDestination = $this->getParameter('DirAPE');
            $prefixeAPE = $this->getParameter('prefixeAPE');

            $nomDestination = $prefixeAPE . '_' . $siret . '_' . $time . '.' . $ext;
            $emplacement = $repertoireDestination . $nomDestination;

            try {

                if (!file_exists($repertoireDestination)) {
                    throw new Exception("Fichier non déplacé");
                }

                move_uploaded_file($file, $emplacement);

                $histo = new Historique('Dépot', 'Document', $user->getUsername() . ' a déposé le document ' . $nom, $user);

                $doc = new DepotDocument($nom, $emplacement, $objThematique, $objInterlocuteur, $this->getUser());
                $em->persist($doc);
                $em->persist($histo);

                try {
                    $em->flush();
                    return new JsonResponse("Fichier enregistré !");
                } catch (Exception $e) {
                    $this->sendErrorFileUploadToAdmin($e->getMessage());
                    return new JsonResponse($e->getMessage(), 500);
                }
            } catch (Exception $e) {
                // si echec du move
                $this->sendErrorFileUploadToAdmin($e->getMessage());
                return new JsonResponse($e->getMessage(), 500);
            }
        } elseif ($thematique == "DPF") {

            $dirBatchDPF = $this->getParameter('dirBatchDPF');
            $batchDPF = $this->getParameter('batchDPF');

            $repertoireDestination = $this->getParameter('DirDPF');
            $prefixeDPF = $this->getParameter('prefixeDPF');

            $nomDestination = $prefixeDPF . '_' . $siret . '_' . $time . '.' . $ext;
            $emplacement = $repertoireDestination . $nomDestination;
            $tentative = 0;

            $wcloud = $this->get('translator')->trans('MESSAGE_CLOUD_DEPOT_DOC');

            try {
                if (!file_exists($repertoireDestination)) {
                    throw new Exception("espace de stockage non disponible");
                }
                do {
                    $wres = move_uploaded_file($file, $emplacement);
                    $tentative = $tentative + 1;
                } while ((!$wres) && ($tentative < 2));
                
                if (!$wres) {
                    //Remarque : la propostion du cloud est condionnée par le mot clé "CLOUD" qui doit être présent dans la JsonReponse ci-dessous.
                    return new JsonResponse("Proposer le CLOUD : " . $wcloud);
                } else {

                    if (!file_exists($emplacement)) {
                        throw new Exception("Fichier ZIP non déposé");
                    }

                    if (!file_exists($dirBatchDPF . $batchDPF)) {
                        throw new Exception("Contrôle de stockage non disponible");
                    }

                    $output = -1;
                    $taboutput = '';
                    exec("sh " . $dirBatchDPF . $batchDPF . " " . $emplacement, $taboutput, $output);

                    if ($output == 100) {
                        throw new Exception("Votre ZIP n est pas conforme il ne contient pas de fichier XLS ");
                    } else {

                        $histo = new Historique('Dépot', 'Document', $user->getUsername() . ' a déposé le document ' . $nom, $user);

                        $doc = new DepotDocument($nom, $emplacement, $objThematique, $objInterlocuteur, $this->getUser());
                        $em->persist($doc);
                        $em->persist($histo);

                        try {
                            $em->flush();
                            return new JsonResponse("Fichier enregistré !");
                        } catch (Exception $e) {
                            $this->sendErrorFileUploadToAdmin($e->getMessage());
                            return new JsonResponse($e->getMessage(), 500);
                        }
                        return new JsonResponse(utf8_decode('Votre fichier est conforme au format attendu : il est accepté'));
                    }
                }
            } catch (Exception $e) {
                // si echec du move
                $this->sendErrorFileUploadToAdmin($e->getMessage());
                return new JsonResponse($e->getMessage(), 500);
            }
        } else {
            return new JsonResponse('La thématique n\'a pas été reconnue', 500);
        }
    }

    /**
     * @param Request $request
     * @Route("/{type}/download/{id}", name="downloadFile")
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function downloadFileAction(Request $request, $id, $type) {
        $doc = $this->getDoctrine();
        if ($type == "dispo") {
            $document = $doc->getRepository("AppBundle:DocumentDisposition")->find($id);
            $explodePath = explode("/", $document->getEmplacement());
            $realName = end($explodePath);
            $log = new TelechargementDocumentDisposition($document, $this->getUser());
            $histo = new Historique('Téléchargement', 'DocumentDispo', 'document "' . $document->getNom() . '" (' . $realName . ') téléchargé', $this->getUser());
            $em = $doc->getManager();
            $em->persist($log);
            $em->persist($histo);
            $em->flush();
        } elseif ($type == 'depot') {
            $document = $doc->getRepository("AppBundle:DepotDocument")->find($id);
            $explodePath = explode("/", $document->getEmplacement());
            $realName = end($explodePath);
        } elseif ($type == 'explorer') {
            $path = 'explorer';
            $realName = basename($this->getParameter('boutonExplorer'));
        } else {
            $this->get('session')->getFlashBag()->add('error', $this->get('translator')->trans('FILE_NOT_FOUND'));

            return $this->redirect($request->headers->get('referer'));
        }
        #35390
//        if (strpos($document->getEmplacement(), $document->getNom()) !== false) {

        if ($path !== 'explorer') {
            $path = $this->getParameter('Kernel') . $document->getEmplacement();
        } else {
            $path = $this->getParameter('boutonExplorer');
        }

//        } else {
//            $path = $this->getParameter('Kernel') . $document->getEmplacement() . $document->getNom();
//        }

        if (empty($path)) {
            $this->get('session')->getFlashBag()->add('error', $this->get('translator')->trans('FILE_NOT_FOUND'));

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

        try {
            $response = new BinaryFileResponse($path);
        } catch (Exception $e) {
            $this->get('session')->getFlashBag()->add('error', $this->get('translator')->trans('FILE_NOT_FOUND'));

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

        // 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->isSupported()) {
            // Guess the mimetype of the file according to the extension of the file
            $response->headers->set('Content-Type', $mimeTypeGuesser->guess($path));
        } 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,
                $realName
        );
        return $response;
    }

    private function sendErrorFileUploadToAdmin($output) {
        $this->get('aeap.mailer')->sendMail('Erreur dépot des documents', $this->getParameter("mailer_admin"), '@App/Email/error_upload_files.html.twig', [
            'error_msg' => $output
        ]);
    }

}
