<?php

namespace Webkul\WebkulCsvImportBundle\Controller\Rest;

use Oro\Bundle\ConfigBundle\Entity\ConfigValue;
use Oro\Bundle\SecurityBundle\Annotation\AclAncestor;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Validator\Constraints\NotBlank;
use Webkul\WebkulCsvImportBundle\Entity\TemplateConfiguration;

/**
 * Configuration rest controller in charge of the Akeneo Custom Csv Import configuration managements
 */
class ConfigurationController extends AbstractController
{
    const SECTION = 'webkul_csv_import_connector';

    public function getActiveCurrenciesAction()
    {
        $currencies = [];
        $repo = $this->getDoctrine()->getRepository('PimCatalogBundle:Currency');
        $codes = $repo->getActivatedCurrencyCodes();

        foreach (Intl::getCurrencyBundle()->getCurrencyNames() as $currencyCode => $currencyName) {
            foreach ($codes as $code) {
                if ($currencyCode == $code) {
                    $currencies[$currencyCode] = $currencyName;
                }
            }
        }

        return new JsonResponse($currencies);
    }

    public function getLogFileAction()
    {
        $log_dir = $this->getParameter('logs_dir');
        $env = $this->getParameter('kernel.environment');
        $path = $log_dir . "/webkul_csvimport_batch." . $env . ".log";
        $fs = new Filesystem();

        if (!$fs->exists($path)) {
            $fs->touch($path);
        }

        $response = new Response();
        $response->headers->set('Content-type', 'application/octet-stream');
        $response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', "webkul_csvimport_batch." . $env . ".log"));
        $response->setContent(file_get_contents($path));
        $response->setStatusCode(200);
        $response->headers->set('Content-Transfer-Encoding', 'binary');
        $response->headers->set('Pragma', 'no-cache');
        $response->headers->set('Expires', '0');

        return $response;
    }

    /**
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function createTemplateAction(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $params = json_decode($request->getContent(), true);
        $form = $this->getConfigForm();
        $form->submit($params);
        $form->handleRequest($request);
        $host = $request->getHost();
        $serverdetail = [
            'hostname' => $request->getHost(),
            'scheme'   => $request->getScheme(),
        ];
        $rawValues = [
            "csvImportMapping" => [
                "extraMapping" => [
                    "categoryFieldName" => "categories",
                    "familyFieldName" => "family",
                    "enabledFieldName" => "enabled",
                    "parentCode" => "parent",
                    "familyVariantFieldName" => "family_variant",
                    "multiValueSeperator" => ",",
                    "productFormatSeperator" => "|",
                    "variantFormatSeperator" => ",",
                    "modelProductType" => "simple",
                    "simpleProductType" => "model",
                    "productTypeFieldName" => "type",
                ],
            ],
        ];

        if ($form->isSubmitted() && $form->isValid()) {
            $repo = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration');
            $configValue = $repo->findOneBy([
                'name' => $params['name']
            ]);

            if ($configValue) {
                return new JsonResponse(['name' => 'This value is already used.'], RESPONSE::HTTP_BAD_REQUEST);
            }

            $configValue = new TemplateConfiguration();
            $configValue->setName($params['name']);
            $configValue->setRawValues(json_encode($rawValues));
            $em->persist($configValue);
            $em->flush();
            $oroRepo = $em->getRepository('OroConfigBundle:ConfigValue');

            foreach ($serverdetail as $key => $value) {
                $field = $oroRepo->findOneBy([
                    'section' => self::SECTION,
                    'name' => $key
                ]);

                if (!$field) {
                    $field = new ConfigValue();
                    $field->setName($key);
                    $field->setSection(self::SECTION);
                }

                $field->setValue($value);
                $em->persist($field);
                $em->flush();
            }
        } else {
            return new JsonResponse($this->getFormErrors($form), RESPONSE::HTTP_BAD_REQUEST);
        }

        return new JsonResponse([
            'meta' => [
                'id' => $configValue->getId()
            ]
        ]);
    }

    /**
     * Get Template Action
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function getTemplateAction(Request $request, $identifier)
    {
        $templates = [];
        $cacheDriver = new \Doctrine\Common\Cache\ArrayCache();
        $deleted = $cacheDriver->deleteAll();
        $em = $this->getDoctrine()->getManager();
        $mapping = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration')->find($identifier);
        $templates['templatename'] = $mapping ? $mapping->getName() : '';
        $templates['rawValues'] = $mapping ? json_decode($mapping->getRawValues(), true) : [];
        $templates['id'] = $mapping ? $mapping->getId() : '';

        return new JsonResponse($templates);
    }

    /**
     * Get template
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function getActiveTemplateAction()
    {
        $data = [];
        $em = $this->getDoctrine()->getManager();
        $stores = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration')->findBy(['active' => 1]);

        foreach ($stores as $store) {
            $data[$store->getId()] = $store->getName();
        }

        return new JsonResponse($data);
    }

    /**
     * Update template
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function updateTemplateAction(Request $request, $identifier)
    {
        $em = $this->getDoctrine()->getManager();
        $params = json_decode($request->getContent(), true);
        $form = $this->getConfigForm();
        $form->submit($params);
        $form->handleRequest($request);

        if ($form->isSubmitted()) {
            if ($params) {
                $repo = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration');
                $configValue = $repo->findOneBy([
                    'name' => $params['templatename'],
                ]);

                if ($params['rawValues'] == null || (isset($params['rawValues']['csvImportMapping']) || isset($params['rawValues']['csvImportMapping']['extraMapping']))) {
                    if (empty($params['rawValues']['csvImportMapping']['extraMapping']['categoryFieldName'])) {
                        return new JsonResponse(['categoryFieldName' => 'Category field should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['familyFieldName'])) {
                        return new JsonResponse(['familyFieldName' => 'Family should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['familyVariantFieldName'])) {
                        return new JsonResponse(['familyVariantFieldName' => 'Family variant should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['enabledFieldName'])) {
                        return new JsonResponse(['enabledFieldName' => 'Product Enabled field should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['modelProductType'])) {
                        return new JsonResponse(['modelProductType' => 'Product type field should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['simpleProductType'])) {
                        return new JsonResponse(['simpleProductType' => 'Product model type field should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                    } elseif (empty($params['rawValues']['csvImportMapping']['extraMapping']['productTypeFieldName']))
                        return new JsonResponse(['productTypeFieldName' => 'Type field should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
                }

                $productFormatSeperator = $params['rawValues']['csvImportMapping']['extraMapping']['productFormatSeperator'];
                $variantSeprator = $params['rawValues']['csvImportMapping']['extraMapping']['variantFormatSeperator'];
                $multiValueSeprator = $params['rawValues']['csvImportMapping']['extraMapping']['multiValueSeperator'];
                $allowedValues = array('-', '=', '|', ',');
                $allowedMvsValues = array('-', '=', '|', ',', '\\', '/');

                if (!empty($productFormatSeperator) && !in_array($productFormatSeperator, $allowedValues)) {
                    return new JsonResponse(['productFormatSeperator' => 'Product formate seprator value is invalid, check the tooltip for valid formate seprators'], RESPONSE::HTTP_BAD_REQUEST);
                }

                if (!empty($variantSeprator) && !in_array($variantSeprator, $allowedValues)) {
                    return new JsonResponse(['variantFormatSeperator' => 'Variant formate seprator value is invalid, check the tooltip for valid formate seprators'], RESPONSE::HTTP_BAD_REQUEST);
                }

                if (!empty($multiValueSeprator) && !in_array($multiValueSeprator, $allowedMvsValues)) {
                    return new JsonResponse(['multiValueSeperator' => 'Multi value seprator is invalid, check the tooltip for valid seprators'], RESPONSE::HTTP_BAD_REQUEST);
                }

                if ($configValue && !$configValue->getId() == $identifier) {
                    return new JsonResponse(['name' => 'This value is already used.'], RESPONSE::HTTP_BAD_REQUEST);
                } else {
                    $configValue = $repo->findOneBy([
                        'id' => $identifier
                    ]);
                    $configValue->setName($params['templatename']);
                    $configValue->setRawValues(json_encode($params['rawValues']));
                    $em->persist($configValue);
                    $em->flush();
                }
            } else {
                return new JsonResponse(['name' => 'This value should not be blank.'], RESPONSE::HTTP_BAD_REQUEST);
            }
        } else {
            return new JsonResponse($this->getFormErrors($form), RESPONSE::HTTP_BAD_REQUEST);
        }

        return new JsonResponse(['successful' => true]);
    }

    /**
     * toogle status
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function toggleStatusAction($id, Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $template = $em->getRepository(TemplateConfiguration::class)->findOneById($id);

        if ($template) {
            $template->setActive($template->getActive() ? 0 : 1);
            $em->persist($template);
            $em->flush();
        }

        if (!$request->isXmlHttpRequest()) {
            return $this->redirect($this->generateUrl('webkul_csv_import_connector_configuration'));
        }

        return new JsonResponse(['successful' => true]);
    }

    /**
     * Remove Template
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function deleteTemplateAction($id)
    {
        $em = $this->getDoctrine()->getManager();
        $mapping = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration')->find($id);

        if (!$mapping) {
            throw new NotFoundHttpException(
                sprintf('Instance with id "%s" not found', $id)
            );
        }

        $em->remove($mapping);
        $em->flush();

        return new Response(null, Response::HTTP_NO_CONTENT);
    }

    /**
     * Remove Multiple Template
     *
     * @AclAncestor("webkul_csv_import_connector_configuration")
     *
     * @return JsonResponse
     */
    public function massDeleteAction(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        $mapping = $em->getRepository('WebkulCsvImportBundle:TemplateConfiguration')->find($id);

        if (!$mapping) {
            throw new NotFoundHttpException(
                sprintf('Instance with id "%s" not found', $id)
            );
        }

        $em->remove($mapping);
        $em->flush();

        return new Response(null, Response::HTTP_NO_CONTENT);
    }

    /**
     * GET Job Instace class versionwise
     * @param Request $request
     *
     * @return JsonResponse
     */
    public function getJobInstanceClassAction(Request $request)
    {
        if (!$request->isXmlHttpRequest()) {
            return new RedirectResponse('/');
        }

        $jobInstanceClass = 'Akeneo\Tool\Component\Batch\Model\JobInstance';

        return new JsonResponse(['history_class' => $jobInstanceClass]);
    }

    private function getConfigForm()
    {
        $form = $this->createFormBuilder(null, [
            'allow_extra_fields' => true,
            'csrf_protection' => false
        ]);

        foreach ($this->getTemplateWithContraints() as $field => $constraint) {
            $form->add($field, null, [
                'constraints' => is_array($constraint) ? $constraint : [
                    $constraint
                ]
            ]);
        }

        return $form->getForm();
    }

    private function getTemplateWithContraints()
    {
        return [
            'name' => [new NotBlank()],
        ];
    }

    private function getFormErrors($form)
    {
        $errorContext = [];

        foreach ($form->getErrors(true) as $key => $error) {
            $errorContext[$error->getOrigin()->getName()] = $error->getMessage();
        }

        return $errorContext;
    }
}
