<?php
/**
 * Created by PhpStorm.
 * User: danielknudsen
 * Date: 05.04.18
 * Time: 13:09
 */
namespace App\Controller;

use App\Entity\DinAsset;
use App\Entity\DinAssetBenchmark;
use App\Entity\DinAssetTask;
use App\Entity\User;
use App\Entity\UserWorksheet;
use App\Entity\UserWorksheetTask;
use App\Repository\UserRepository;
use App\Service\CalculatorService;
use App\Utils\Utils;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xls;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;

/**
 * @Security("is_granted('ROLE_USER')")
 */
class UserController extends AbstractController
{

    /**
     * @Route("/start", name="start")
     */
    public function showStart()
    {
        /** @var User $user */
        $user = $this->getUser();

        $worksheets = $user->getWorksheets();
        $cntWorksheets = count($worksheets);
        $numWorksheetsLeft =  $user->getMaxWorksheets() - $cntWorksheets;

        $resWorksheets = $worksheets->toArray();
        usort($resWorksheets, function(UserWorksheet $a, UserWorksheet $b) {
            return $a->getCreationDate() > $b->getCreationDate();
        });

        return $this->render('pages/start.html.twig',
            [
                'worksheets' => $resWorksheets,
                'numWorksheetsLeft' => $numWorksheetsLeft,
            ]
        );
    }

    /**
     * @Route("/risk-analysis", name="risk_analysis")
     *
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \Exception
     */
    public function showRiskAnalysis()
    {
        $em = $this->getDoctrine()->getManager();

        /** @var User $user */
        $user = $this->getUser();

        $dinAssets = $em->getRepository(DinAsset::class)->findAll();
        /** @var DinAsset $initialDinAsset */
        $initialDinAsset = null;
        $benchmarkValues = [];
        if (count($dinAssets) > 0) {
            $initialDinAsset = $dinAssets[0];
            $benchmarkValues = $initialDinAsset->getBenchMarkSelectValues();
        }

        return $this->render('pages/risk_analysis.html.twig',
            [
                'initialDinAsset' => $initialDinAsset,
                'benchmarkValues' => $benchmarkValues,
                'dinAssets' => $dinAssets,
                'riskFailure' => Utils::$riskFailure,
                'riskCosts' => Utils::$riskCosts,
            ]
        );
    }

    /**
     * @Route("/get-benchmark-data", name="get_benchmark_data")
     */
    public function getBenchmarkData(Request $request)
    {
        $assetId = $request->query->get('assetId');
        /** @var DinAsset $dinAsset */
        $dinAsset = $this->getDoctrine()->getRepository(DinAsset::class)->find($assetId);

        if (null === $dinAsset) {
            return new JsonResponse(null, JsonResponse::HTTP_BAD_REQUEST);
        }

        $res = [];
        $res['benchmarkValues'] = $dinAsset->getBenchMarkSelectValues();
        return $this->json($res);
    }

    /**
     * @Route("/calculate-risk", name="calculate_risk")
     */
    public function calculateRisk(Request $request, CalculatorService $calculatorService)
    {
        $params = $request->request->all();
        $asset = $this->getDoctrine()->getRepository(DinAsset::class)->find($params['asset']);
        $benchMark = null;
        if (array_key_exists('benchmark', $params)) {
            $benchMark = $this->getDoctrine()->getRepository(DinAssetBenchmark::class)->find($params['benchmark']);
        }
        $res = $calculatorService->calculateRisk($params, $asset, $benchMark);
        return $this->json($res);
    }

    /**
     * @Route("/create-worksheet", name="create_worksheet")
     */
    public function createWorksheet(Request $request, CalculatorService $calculatorService)
    {
        /** @var User $user */
        $user = $this->getUser();
        $em = $this->getDoctrine()->getManager();

        if (count($user->getWorksheets()) >= $user->getMaxWorksheets()) {
            return new JsonResponse(null, JsonResponse::HTTP_BAD_REQUEST);
        }
        $params = $request->request->all();

        /** @var DinAsset $asset */
        $asset = $em->getRepository(DinAsset::class)->find($params['asset']);
        if ($asset === null) {
            return new JsonResponse(null, JsonResponse::HTTP_BAD_REQUEST);
        }
        $assetTasks = $asset->getTasks();

        $asset = $this->getDoctrine()->getRepository(DinAsset::class)->find($params['asset']);
        $benchMark = null;
        $bandwidth = null;
        if (array_key_exists('benchmark', $params)) {
            $benchMark = $this->getDoctrine()->getRepository(DinAssetBenchmark::class)->find($params['benchmark']);
            $bandwidth = $benchMark->getBandwidth();
        }
        $calculation = $calculatorService->calculateRisk($params, $asset, $benchMark);
        $failureProbability = Utils::$riskFailure[$params['failure']][0];
        $failureDamage = Utils::$riskCosts[$params['costs']][0];
        $maintenanceAdvantage = $params['maintenance'];
        $inspectionAdvantage = $params['inspection'];
        $cycle = $params['cycle'];
        $recCycleMaintenance = $calculation['recCycleMaintenance'];
        $recCycleInspection = $calculation['recCycleInspection'];
        $costDiffCurRecPercentage = $calculation['costDiffCurRecPercentage'];
        $costDiffCurCycleRecCycle = $calculation['costDiffCurCycleRecCycle'];

        $em->getConnection()->beginTransaction();
        try {
            $worksheet = new UserWorksheet($user);
            $worksheet->setDinNumber($asset->getDinNumber());
            $worksheet->setDinAssetName($asset->getName());
            $worksheet->setFailureProbability($failureProbability);
            $worksheet->setFailureDamage($failureDamage);
            $worksheet->setMaintenanceAdvantage($maintenanceAdvantage);
            $worksheet->setInspectionAdvantage($inspectionAdvantage);
            $worksheet->setUserCycleMonths($cycle);
            $worksheet->setBandwidth($bandwidth);
            $worksheet->setRecMaintenanceCycleMonths($recCycleMaintenance);
            $worksheet->setRecInspectionCycleMonths($recCycleInspection);
            $worksheet->setDeviationPercentage($costDiffCurRecPercentage);
            $worksheet->setDeviationCosts($costDiffCurCycleRecCycle);

            $em->persist($worksheet);
            $em->flush();

            /** @var DinAssetTask $assetTask */
            foreach ($assetTasks as $assetTask) {
                $worksheetTask = new UserWorksheetTask();
                $worksheetTask->setUserWorksheet($worksheet);
                $worksheetTask->setDelimitation($assetTask->getDelimitation());
                $worksheetTask->setTask($assetTask->getTask());
                $worksheetTask->setInspection($assetTask->getInspection());
                $worksheetTask->setMaintenance($assetTask->getMaintenance());
                $worksheetTask->setService($assetTask->getService());
                $worksheetTask->setExpert($assetTask->getExpert());
                $worksheetTask->setSpecialist($assetTask->getSpecialist());
                $worksheetTask->setSkilledPersonnel($assetTask->getSkilledPersonnel());
                $worksheetTask->setNorm($assetTask->getNorm());
                $em->persist($worksheetTask);
                $em->flush();
            }
            $em->flush();
            $em->getConnection()->commit();

        } catch (\Exception $e) {
            $em->getConnection()->rollBack();
            return new JsonResponse(null, JsonResponse::HTTP_BAD_REQUEST);
        }

        return new JsonResponse($worksheet->getId(), JsonResponse::HTTP_OK);
    }

    /**
     * @Route("/worksheet/{uuid}", name="show_worksheet")
     */
    public function showWorksheet($uuid)
    {
        /** @var User $user */
        $user = $this->getUser();
        $em = $this->getDoctrine()->getManager();

        /** @var UserWorksheet $worksheet */
        $worksheet = $em->getRepository(UserWorksheet::class)->findOneBy(['id' => $uuid]);

        if (null === $worksheet || $user->getId() !== $worksheet->getUser()->getId()) {
            throw new \Exception('not allowed or not exists');
        }

        return $this->render('pages/worksheet.html.twig',
            [
                'worksheet' => $worksheet,
                'sortedWorksheetTasks' => UserRepository::getSortedWorksheetTasks($worksheet),
                'isPdf' => false
            ]
        );
    }

    /**
     * @Route("/download/{uuid}", name="download")
     */
    public function downloadPdf(Environment $twig, $uuid)
    {
        ini_set('max_execution_time', '60');

        /** @var User $user */
        $user = $this->getUser();
        $em = $this->getDoctrine()->getManager();

        /** @var UserWorksheet $worksheet */
        $worksheet = $em->getRepository(UserWorksheet::class)->findOneBy(['id' => $uuid]);

        if (null === $worksheet || $user->getId() !== $worksheet->getUser()->getId()) {
            throw new \Exception('not allowed or not exists');
        }

        $dompdf = UserRepository::renderWorksheetPDF($twig, $worksheet);

        // Output the generated PDF to Browser (force download)
        $fileName = "Arbeitskarte_".$worksheet->getCreationDate()->format('Y-m-d_H-i');
        $dompdf->stream($fileName, [
            "Attachment" => true
        ]);
        // NOTE: This is required, since method need a result!
        exit(0);
    }

    /**
     * @Route("/excel/{uuid}", name="excel")
     */
    public function exportExcel($uuid)
    {
        /** @var User $user */
        $user = $this->getUser();
        $em = $this->getDoctrine()->getManager();

        /** @var UserWorksheet $worksheet */
        $worksheet = $em->getRepository(UserWorksheet::class)->findOneBy(['id' => $uuid]);

        if (null === $worksheet || $user->getId() !== $worksheet->getUser()->getId()) {
            throw new \Exception('not allowed or not exists');
        }

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $sheet->getStyle('A1:I200')->applyFromArray(
            [
                'alignment' => [
                    'horizontal' => Alignment::HORIZONTAL_LEFT,
                    'wrapText' => true
                ],
                'font' => [
                    'size' => 12,
                    'name' => 'Arial'
                ],
            ]
        );
        $sheet->getColumnDimension('A')->setWidth(60);
        $sheet->getColumnDimension('B')->setWidth(50);
        $sheet->getColumnDimension('C')->setWidth(20);
        $sheet->getColumnDimension('D')->setWidth(20);
        $sheet->getColumnDimension('E')->setWidth(20);
        $sheet->getColumnDimension('F')->setWidth(20);
        $sheet->getColumnDimension('G')->setWidth(20);
        $sheet->getColumnDimension('H')->setWidth(20);
        $sheet->getColumnDimension('I')->setWidth(50);

        $sheet->getStyle('A1')->getFont()->setSize(18);
        $sheet->setCellValue('A1', 'Arbeitsblatt');
        $sheet->setCellValue('B1', 'erstellt am: ' . $worksheet->getCreationDate()->format('d.m.Y H:i'));
        $sheet->getStyle('A3')->getFont()->setSize(16);
        $sheet->setCellValue('A3', $worksheet->getDinNumber(). " ".$worksheet->getDinAssetName());

        $sheet->getStyle('A5')->getFont()->setSize(16);
        $sheet->setCellValue('A5', 'Risikoanalyse');
        $sheet->setCellValue('A6', 'Wie hoch ist die Ausfallwahrscheinlichkeit?');
        $sheet->setCellValue('B6', $worksheet->getFailureProbability());
        $sheet->setCellValue('A7', 'Wie hoch ist der Schaden bei Ausfall?');
        $sheet->setCellValue('B7', $worksheet->getFailureDamage());

        $sheet->getStyle('A9')->getFont()->setSize(16);
        $sheet->setCellValue('A9', 'Optimierungscheck');
        $sheet->setCellValue('A10', 'Wird durch die Wartung der Abnutzungsvorrat positiv beeinflusst?');
        $sheet->setCellValue('B10', $worksheet->getMaintenanceAdvantage() ? 'Ja' : 'Nein');
        $sheet->setCellValue('A11', 'Kann durch eine Inspektion der Zustand der Anlage erkannt werden?');
        $sheet->setCellValue('B11', $worksheet->getInspectionAdvantage() ? 'Ja' : 'Nein');

        $sheet->getStyle('A13')->getFont()->setSize(16);
        $sheet->setCellValue('A13', 'Zyklus und Größencluster');
        $sheet->setCellValue('A14', 'Aktueller Zyklus (in Monaten)');
        $sheet->setCellValue('B14', $worksheet->getUserCycleMonths());
        $sheet->setCellValue('A15', 'Größencluster');
        $sheet->setCellValue('B15', $worksheet->getBandwidth());

        $sheet->getStyle('A17')->getFont()->setSize(16);
        $sheet->setCellValue('A17', 'Ergebnis');
        $sheet->setCellValue('A18', 'Empfehlung Wartung (in Monaten)');
        $sheet->setCellValue('B18', $worksheet->getRecMaintenanceCycleMonths());
        $sheet->setCellValue('A19', 'Empfehlung Inspektion (in Monaten)');
        $sheet->setCellValue('B19', $worksheet->getRecInspectionCycleMonths());
        $sheet->setCellValue('A20', 'Einsparpotential p.a. (%)');
        $sheet->setCellValue('B20', $worksheet->getDeviationPercentage() * 100);
        $sheet->setCellValue('A21', 'Einsparpotential p.a. (€)');
        $sheet->setCellValue('B21', $worksheet->getDeviationCosts());

        $sheet->getStyle('A23')->getFont()->setSize(16);
        $sheet->setCellValue('A23', 'Tätigkeiten');
        $sheet->getStyle('A23:I24')->getFont()->setSize(14);
        $sheet->getStyle('A24:I24')->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('ffa4ffa4');
        $sheet->setCellValue('A24', 'Baugruppe');
        $sheet->setCellValue('B24', 'Aufgabe');
        $sheet->setCellValue('C24', 'Inspektion');
        $sheet->setCellValue('D24', 'Wartung');
        $sheet->setCellValue('E24', 'Instandsetzung');
        $sheet->setCellValue('F24', 'Sachverständiger');
        $sheet->setCellValue('G24', 'Sachkundige');
        $sheet->setCellValue('H24', 'Fachkraft');
        $sheet->setCellValue('I24', 'Normative Grundlage');

        $row = 25;
        $worksheetTasks = UserRepository::getSortedWorksheetTasks($worksheet);
        /** @var UserWorksheetTask $task */
        foreach ($worksheetTasks as $task) {
            $sheet->setCellValue('A'.$row, (($row-24) .". ") . ($task->getDelimitation() ?? " - "));
            $sheet->setCellValue('B'.$row, $task->getTask());
            $sheet->setCellValue('C'.$row, $task->getInspection() ? 'Ja' : 'Nein');
            $sheet->setCellValue('D'.$row, $task->getMaintenance() ? 'Ja' : 'Nein');
            $sheet->setCellValue('E'.$row, $task->getService() ? 'Ja' : 'Nein');
            $sheet->setCellValue('F'.$row, $task->getExpert() ? 'Ja' : 'Nein');
            $sheet->setCellValue('G'.$row, $task->getSpecialist() ? 'Ja' : 'Nein');
            $sheet->setCellValue('H'.$row, $task->getSkilledPersonnel() ? 'Ja' : 'Nein');
            $sheet->setCellValue('I'.$row, $task->getNorm());
            $row++;
        }

        $writer = new Xls($spreadsheet);

        $response =  new StreamedResponse(
            function () use ($writer) {
                $writer->save('php://output');
            }
        );
        $filename = "Arbeitskarte_".$worksheet->getCreationDate()->format('Y-m-d_H-i');
        $response->headers->set('Content-Type', 'application/vnd.ms-excel');
        $response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'.xls"');
        $response->headers->set('Cache-Control','max-age=0');
        return $response;
    }

    /**
     * @Route("/legal-page", name="legal_page", methods={"GET"})
     */
    public function legalPage()
    {
        return $this->render('pages/legal.html.twig', []);
    }

    /**
     * @Route("/accept-legal-terms", name="accept_legal_terms", methods={"GET"})
     */
    public function acceptlegalTerms()
    {
        /** @var User $user */
        $user = $this->getUser();
        if ($user) {
            $user->setAcceptedLegal(true);
            $user->setAcceptedTerms(true);
            $this->getDoctrine()->getManager()->flush();
            return $this->redirectToRoute('start');
        }
        return $this->redirectToRoute('index');
    }
}