<?php

namespace App\Controller\Base;

use App\Electronico\Comprobante;
use App\Entity\Model\AbstractRetencion;
use App\Entity\Model\ItemRetencion;
use App\Entity\Model\Retencion;
use App\Service\EmFactory;
use App\Util\RestApiFunciones;
use JMS\Serializer\SerializerBuilder;
use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;

abstract class AbstractRetencionController extends AbstractController
{

    protected function descargaBulk($retencioness)
    {
        $Datos = 'cliente;identificacion;email;direccion;factura;f_emision;f_autorizacion;neto;iva;basecero;baseiva;total;anulado;socio';
        $Datos .= "\r\n";

        foreach ($retencioness as $fila) {

            $item = $fila[0];
            //$item = new Retencion();
            try {

                $cliente = $item->getCustomerName();
                $identificacion = $item->getCustomerIdentification();
                $email = $item->getCustomerEmail();
                $direccion = $item->getInvoicingAddress();
                //$telefono = $item->getCustomer()->getTelefono();
                $factura = $item->label();
                $emision = $item->getIssueDate()->format('d/m/Y');

                $f_auto = "";
                if ($item->getAutorizado())
                    $f_auto = $item->getFechaAutorizacion();

                $neto = $item->getNetAmount();
                $iva = $item->getTaxAmount();
                $basecero = $item->getBasecero();
                $baseiva = $item->getBaseiva();
                $total = $item->getGrossAmount();

                $anulado = "";
                if ($item->getAnulado())
                    $anulado = "SI";

                $socio = $item->getUsuario()->getName();
                $Datos .= "$cliente;" .
                    "$identificacion;" .
                    "$email;" .
                    "$direccion;" .
                    //"$telefono;" .
                    "$factura;" .
                    "$emision;" .
                    "$f_auto;" .
                    "$neto;" .
                    "$iva;" .
                    "$basecero;" .
                    "$baseiva;" .
                    "$total;" .
                    "$anulado;" .
                    "$socio;";

                $Datos .= "\r\n";

            } catch (\Exception $e) {
                $resp = $e->getMessage();
            }
        }

        return $Datos;
    }

    protected function generarXml(Retencion $retencion)
    {
        try {
            $empresa = $retencion->getEmpresa();

            $serie = $retencion->getSerie();

            $numero = str_pad($retencion->getNumber(), 9, "0", STR_PAD_LEFT);

            $emisor = new Comprobante(null, $empresa, $serie);

            $resp = $emisor->generaClave($retencion->getIssueDate()->format('d/m/Y'), "07", $numero);

            if ($resp != null) {
                $this->addTranslatedMessage($resp, 'danger');
                return $retencion;
            }

            if ($emisor->getClaveAcceso() == null) {
                $this->addTranslatedMessage("error generacion clave de acceso");
                return $retencion;
            }

            $retencion->setClaveAcceso($emisor->getClaveAcceso());

            $error = false;

            $comprobRetencion = $emisor->generarXmlRetencion($retencion, $error);

            if ($error) {
                $this->addTranslatedMessage($error, 'danger');
                return $retencion;
            }

            try {
                $serializer = SerializerBuilder::create()->build();
                $xml = $serializer->serialize($comprobRetencion, 'xml');
                $xml = trim(preg_replace('/\s+/', ' ', $xml));
                $retencion->setXml($xml);
            } catch (\Exception $e) {
                $this->addTranslatedMessage($e->getMessage(), 'danger');
                return null;
            }

            $em = $this->getDoctrine()->getManager();
            $em->persist($retencion);
            $em->flush();

        } catch (\Exception $e) {
            $this->addTranslatedMessage($e->getMessage());
            return null;
        }

        return $retencion;
    }

    protected function addTranslatedMessage($message, $status = 'success')
    {
        $this->get('session')
            ->getFlashBag()
            ->add($status, $this->translator->trans($message, [], 'retencion'));
    }

    protected function getRetencionPrintPdfHtml(Retencion $retenciones, $print = false)
    {
        $settings = $this->getDoctrine()
            ->getRepository('SiwappConfigBundle:Property')
            ->getAll();
        $factura = null;
        /*try {

            $factura = $this->container->get('jms_serializer')->deserialize($retenciones->getXml(),'App\Entity\Model\Facturas\Factura', 'xml');
        } catch (Exception $e) {

        }
        */

        return $this->renderView('SiwappRetencionBundle:Retencion:print.html.twig', [
            'retenciones' => $retenciones,
            'settings' => $settings,
            'print' => $print,
            'factura' => $factura
        ]);
    }

    protected function bulkDelete(array $retencioness)
    {
        $em = $this->getDoctrine()->getManager();
        foreach ($retencioness as $retenciones) {
            if ($retenciones->getAmbiente() == 1)
                $em->remove($retenciones);
            else {
                $this->addTranslatedMessage('NO SE PUEDEN ELIMINAR RETENCIONES EN AMBIENTE PRODUCCION', 'danger');
                return $this->redirect($this->generateUrl('retencion_index'));
            }
        }
        $em->flush();
        $this->addTranslatedMessage('flash.bulk_deleted');

        return $this->redirect($this->generateUrl('retencion_index'));
    }

    protected function bulkPdf(array $retencioness)
    {
        $pages = [];
        foreach ($retencioness as $retenciones) {
            $pages[] = $this->getRetencionPrintPdfHtml($retenciones);
        }

        $html = $this->get('siwapp_core.html_page_merger')->merge($pages, '<div class="pagebreak"> </div>');
        $pdf = $this->getPdf($html);

        return new Response($pdf, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="Retencions.pdf"'
        ]);
    }

    protected function bulkPrint(array $retencioness)
    {
        $pages = [];
        foreach ($retencioness as $retenciones) {
            $pages[] = $this->getRetencionPrintPdfHtml($retenciones, true);
        }

        $html = $this->get('siwapp_core.html_page_merger')->merge($pages, '<div class="pagebreak"> </div>');

        return new Response($html);
    }

    protected function bulkEmail(array $retencioness)
    {
        $em = $this->getDoctrine()->getManager();
        foreach ($retencioness as $retenciones) {
            $message = $this->getEmailMessage($retenciones);
            $result = $this->get('mailer')->send($message);
            if ($result) {
                $retenciones->setSentByEmail(true);
                $em->persist($retenciones);
            }
        }
        $em->flush();
        $this->addTranslatedMessage('flash.bulk_emailed');

        return $this->redirect($this->generateUrl('retenciones_index'));
    }

    protected function bulkAutorizar(array $retencioness)
    {
        $em = $this->getDoctrine()->getManager();

        $app_url = $this->getParameter('app_url');
        $ruc = $this->getParameter('ruc');


        foreach ($retencioness as $retenciones) {

            if (!$retenciones->getAutorizado()) {

                $emisor = new Comprobante($app_url, $ruc, null, null, null, null);

                $emisor->setClaveAcceso($retenciones->getClaveAcceso());

                $error = false;
                $resp = $emisor->consultarAutoComprobante($error, 3);

                if ($error) {
                    $this->addTranslatedMessage($resp, 'danger');
                    $retenciones->setSinrespuesta(true);
                    $retenciones->setMensajeError($resp);
                    $em->persist($retenciones);
                    $em->flush();
                } else {
                    if ($resp->autorizado) {
                        $retenciones->setAutorizado(true);
                        $retenciones->setSinrespuesta(false);
                        $retenciones->setMensajeError("");
                        $retenciones->setFechaAutorizacion($resp->fecha);
                        $em->persist($retenciones);
                        $em->flush();

                    } else {
                        $this->addTranslatedMessage($resp, 'danger');
                    }
                }
            }

        }

        //return $this->redirect($this->generateUrl('partnerretenciones_admin_index'));
    }

    protected function consultarAutorizacion(Retencion $retencion)
    {
        $respuesta = null;
        try {
            $em = $this->getDoctrine()->getManager();

            $app_url = $this->getParameter('api_url');

            $error = false;

            $resp = RestApiFunciones::consultarAutoComprobante($error, $app_url, $retencion->getClaveAcceso());

            if ($error) {
                $this->addTranslatedMessage($resp, 'danger');
                $retencion->setSinrespuesta(true);
                $retencion->setMensajeError($resp);
                $em->persist($retencion);
                $em->flush();
            } else {
                if ($resp->autorizado) {
                    $this->addTranslatedMessage('Comprobante autorizado, fecha: ' . $resp->fecha);
                    $retencion->setAutorizado(true);
                    $retencion->setSinrespuesta(false);
                    $retencion->setMensajeError("");
                    $retencion->setFechaAutorizacion($resp->fecha);
                    $retencion->setXmlAutorizado($resp->comprobante);
                    $retencion->setStatus(Retencion::CLOSED);
                    $retencion->setForcefullyClosed(true);
                    $em->persist($retencion);
                    $em->flush();

                } else {
                    $this->addTranslatedMessage($resp, 'danger');
                }
            }


        } catch (\Exception $e) {
            return $e->getMessage();
        }

        return $respuesta;
    }


    protected function getEmailMessage($retencion)
    {
        $em = $this->getDoctrine()->getManager();
        $usuario = $this->get('security.token_storage')->getToken()->getUser();
        $configRepo = $em->getRepository('SiwappConfigBundle:Property');

        /*$pdf = $this->getPdf($html);
    */

        $data = $retencion->getXml();

        $app_url = $this->getParameter('empresas_url');

        $client = new \GuzzleHttp\Client();

        $response = $client->request('POST', $app_url . "rest/cmp/offlinepdf", [
            'body' => $data,
            'headers' => [
                'Accept' => 'application/pdf',
                'Content-Type' => 'application/xml',
                'Authorization' => 'ShaRaPp150108.Xcmp']
        ]);

        if ($response->getStatusCode() == 200) {
            $pdf = $response->getBody();

            $comprobante = $this->get('translator')->trans('retencion.retencion', [], 'SiwappRetencionBundle');

            $html = "<br>Estimado(a), <b>" . $retencion->getCustomerName() . "</b>" .
                "<br><br>Hemos emitido el siguiente comprobante electronico." .
                "<br><br>Documento: <b>" . $comprobante . "</b>" .
                "<br>Numero: <b>" . $retencion->label() . "</b>" .
                "<br>Clave de Acceso: <b>" . $retencion->getClaveAcceso() . "</b>" .
                "<br>Numero Autorizacion: <b>" . $retencion->getClaveAcceso() . "</b>" .
                "<br><br>El documento pdf de su <b>" . $comprobante . "</b>, se encuentra adjunto a este correo." .
                "<br><br>Saludos cordiales," .

                "<br><br>-----" .
                "<br>�0�3Gracias por apoyarnos a servirle mejor y a conservar el medio ambiente!" .
                "<br>Servicio proporcionado por: <a href=\"http://www.sharafac.com\">www.sharafac.com</a>" .
                "<br><br>Las tildes han sido omitidas intencionalmente para evitar problemas de lectura<br><br><br><br>";


            $attachment = new \Swift_Attachment($pdf, $comprobante . '-' . $retencion->label() . '.pdf', 'application/pdf');
            $subject = $comprobante . ': ' . $retencion->label();

            /*$message = \Swift_Message::newInstance()
                ->setSubject($subject)
                ->setFrom($configRepo->get('company_email'), $configRepo->get('company_name'))
                ->setTo($retenciones->getCustomerEmail(), $retenciones->getCustomerName())
                ->setBody($html, 'text/html')
                ->attach($attachment);

            return $message;
            */

            $mailuser = $this->getParameter('mailer_user');
            $mailpass = $this->getParameter('mailer_password');
            $mailhost = $this->getParameter('mailer_host');
            $mailport = $this->getParameter('mailer_port');
            $mailencrypt = $this->getParameter('mailer_encryption');

            $transport = \Swift_SmtpTransport::newInstance()
                ->setUsername($mailuser)->setPassword($mailpass)
                ->setHost($mailhost)
                ->setPort($mailport)->setEncryption($mailencrypt);

            $mailer = \Swift_Mailer::newInstance($transport);

            $message = \Swift_Message::newInstance()
                ->setSubject($subject)
                ->setFrom($mailuser, $usuario->getName())
                ->setTo([$usuario->getEmail(), $retencion->getCustomerEmail() => $retencion->getCustomerName()])
                ->setBody($html, 'text/html')
                ->attach($attachment);;

            $result = $mailer->send($message);

            return $result;

        } else {
            return 0;
        }


    }

    protected function cargarImpuestos(AbstractRetencion $retenciones)
    {
        $baserenta = 0;
        $baseiva = 0;

        foreach ($retenciones->getItems() as $item) {

            $p = $item->getTipoRetencion();
            //$p= new TipoRetencion();

            $base = $item->getBase();
            if ($p->getTipo() === "R") {
                $baserenta += $base;
            } else {
                $baseiva += $base;
            }
            $retenido = $base * ($item->getPorcentaje() / 100);

            $item->setRetenido(round($retenido, 2));
            $item->setDescription($p->getName());
            $item->setPorcentaje($p->getPorcentaje());

        }

        $retenciones->setBaseRenta($baserenta);
        $retenciones->setBaseiva($baseiva);

        return $retenciones;
    }

    protected function generarPdf(Retencion $retencion)
    {
        $filename = 'RE_' . $retencion->getSerie() . "-" . str_pad($retencion->getNumber(), 9, '0', STR_PAD_LEFT) . '.pdf';

        if ($retencion->getAutorizado())
            $xml = $retencion->getXmlAutorizado();
        else
            $xml = $retencion->getXml();

        $app_url = $this->getParameter('api_url');

        $app_url .= 'retencionride.php';

        $error = false;
        $mensaje = "";
        $docPdf = RestApiFunciones::getPdf($error, $app_url, $retencion->getClaveAcceso(), $xml, $mensaje);

        if ($error) {
            $this->addTranslatedMessage('ERRROR AL GENERAR EL PDF, ' . $mensaje, 'danger');
        } else {
            file_put_contents($filename, $docPdf);

            header("Cache-Control: public");
            header("Content-Description: File Transfer");
            header("Content-Disposition: attachment; filename=$filename");
            header("Content-Type: application/pdf");
            header('Content-Length: ' . filesize($filename));
            //header("Content-Transfer-Encoding: binary");
            header('Accept-Ranges: bytes');
            echo $docPdf;

            try {
                unlink($filename);
            } catch (\Exception $ex) {

            }

        }
    }

    protected function delete(Retencion $retencion)
    {
        $em = $this->getDoctrine()->getManager();

        if ($retencion->getAutorizado() && $retencion->getAmbiente() == 2) {
            $this->addTranslatedMessage('Retención no puede ser eliminada, estado: AUTORIZADO, ambiente: PRODUCCION', 'warning');
            return false;
        } else {
            $em->remove($retencion);
            $em->flush();
            $this->addTranslatedMessage('flash.deleted');

            return true;
        }
    }

    protected function enviarMail($email, Retencion $retencion)
    {
        $em = $this->getDoctrine()->getManager();

        $xmlAutorizado = null;

        if ($retencion->getAutorizado())
            $xmlAutorizado = $retencion->getXmlAutorizado();

        $numero = $retencion->getSerie() . '-' . str_pad($retencion->getNumber(), 9, '0', STR_PAD_LEFT);

        $error = false;
        $mensaje = "";

        //$filename = 'FAC_' . $invoice->getSerie() . "-" . str_pad($invoice->getNumber(), 9, '0', STR_PAD_LEFT) . '.pdf';

        if ($retencion->getAutorizado())
            $data = $retencion->getXmlAutorizado();
        else
            $data = $retencion->getXml();

        $app_url = $this->getParameter('api_url');

        $app_url .= 'retencionride.php';

        $docPdf = RestApiFunciones::getPdf($error, $app_url, $retencion->getClaveAcceso(), $data, $mensaje);

        if ($error) {
            $this->addTranslatedMessage('ERRROR AL GENERAR EL PDF, ' . $mensaje, 'danger');
        } else {
            $result = RestApiFunciones::envioMailComprobante(
                $retencion->getProviderName(),
                $numero,
                $retencion->getClaveAcceso(),
                $retencion->getFechaAutorizacion(),
                "Retencion",
                $email,
                $docPdf,
                $xmlAutorizado,
                $retencion->getEmpresa()
            );

            if ($result) {
                $this->addTranslatedMessage('MENSAJE ENVIADO A: ' . $email);
                $retencion->setSentByEmail(true);
                $em->persist($retencion);
                $em->flush();
            } else
                $this->addTranslatedMessage('ERRROR, ' . $result, 'danger');
        }
    }

    protected function getRetencionesTotalsFromPost(array $post, AbstractRetencion $retencion, string $locale): array
    {
        $user = $this->getUser();

        $em = $this->getDoctrine()->getManager();

        $empresaRepo = $em->getRepository('App\Entity\Model\Empresa');
        $empresa = $empresaRepo->findOneByUser($user->getRuc());

        $currency = $empresa == null ? 'USD' : $empresa->getCurrency();
        $formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);
        $transformer = new MoneyToLocalizedStringTransformer(2, true);

        $totals = [];
        foreach ($post['items'] as $index => $postItem) {
            $item = new ItemRetencion();
            //$item->setRetenido($transformer->reverseTransform($postItem['retenido']));
            $item->setBase($postItem['base']);
            //$item->setDiscount(0);

            $porcentaje = 0;
            $retenido = 0;
            if (isset($postItem['tipoRetencion'])) {

                $tipoRetencion = $em->getRepository('App\Entity\Model\TipoRetencion')->find($postItem['tipoRetencion']);

                if ($tipoRetencion != null) {
                    $porcentaje = $tipoRetencion->getPorcentaje();
                    $item->setPorcentaje($porcentaje);

                    $retenido = $postItem['base'] * ($porcentaje / 100);
                    $item->setRetenido($retenido);
                }
            }

            $totals['items'][$index] = [
                'porcentaje' => $porcentaje,
                'retenido' => round($retenido,2),
            ];
            $retencion->addItem($item);
        }

        $retencion->checkAmounts();

        $totals += [
            'retencion_gross_amount' => $formatter->formatCurrency($retencion->getGrossAmount(), $currency),
            //'retencion_porcentaje' => $retencion->getGrossAmount(),
        ];

        return $totals;
    }
}
