<?php

namespace App\Services;

use App\Controllers\Pedidos\Pedido;
use CodeIgniter\Config\BaseService;

use App\Models\Configuracion\MaquinasTarifasImpresionModel;
use App\Models\Clientes\ClientePreciosModel;
use App\Models\Configuracion\MaquinaModel;
use App\Models\Configuracion\PapelImpresionModel;
use App\Models\Configuracion\PapelGenericoModel;
use App\Models\Configuracion\TipoPresupuestoModel;
use App\Models\Configuracion\PapelFormatoModel;

use App\Models\Presupuestos\PresupuestoLineaModel;

use App\Models\Presupuestos\PresupuestoAcabadosModel;
use App\Models\Presupuestos\PresupuestoManipuladosModel;
use App\Models\Presupuestos\PresupuestoEncuadernacionesModel;

use App\Models\Presupuestos\PresupuestoDireccionesModel;
use App\Models\Tarifas\TarifaEnvioModel;



class PresupuestoService extends BaseService
{
    /**
     * CONSTANTES USADAS PARA LOS CALCULOS
     */

    const MARGEN_PAGINAS_ROTATIVA = 15.0;
    const SANGRE_FORMAS = 5.0;
    const SANGRE_FORMAS_CUBIERTA = 20.0;


    public static function getLineaPresupuestoPlana($data)
    {

        $uso = $data['uso'];
        $tipo = $data['tipo'];
        $datosPedido = $data['datosPedido'];
        $cliente_id = $data['cliente_id'];
        $papel = $data['papel'];
        $opciones_papel = $data['opciones_papel'];
        $maquina = $data['maquina'];
        $papel_generico = $data['papel_generico'];
        $isColor = $data['isColor'];
        $a_favor_fibra = $data['a_favor_fibra'];
        $datosTipolog = $data['datosTipolog'];
        $gramaje = $data['gramaje'];


        if ($maquina->is_inkjet) {
            $parametrosInkjet = (object) array(
                'a_favor_fibra' => $a_favor_fibra, // este parametro se cambia para comprobar 
                // en las dos direcciones (menos en rustica fresada que es siempre 1)
                'bnPages' => $isColor ? 0 : $datosPedido->paginas,
                'colorPages' => ($uso == 'guardas') ? $datosPedido->paginas_impresion : ($isColor ? $datosPedido->paginas : 0),
                'rotativa_gota_negro' => 0,
                'rotativa_gota_color' => 0,
            );

            $papelImpresionTipologiaModel = new \App\Models\Configuracion\PapelImpresionTipologiaModel();
            if (is_null($datosTipolog)) {
                $datosTipologias = $papelImpresionTipologiaModel
                    ->findTipologiasForPapelImpresion($papel->id, $parametrosInkjet->colorPages > 0 ? 'color' : 'negro')
                    ->get()->getResultObject();


                if (count($datosTipologias) == 0) {
                    return [];
                }
            } else {
                $datosTipologias = $datosTipolog;
            }
            $parametrosInkjet->rotativa_gota_negro = $datosTipologias[0]->gota_negro;
            $parametrosInkjet->rotativa_gota_color = $datosTipologias[0]->gota_color;
            $parametrosInkjet->rotativa_negro = $datosTipologias[0]->negro;
            $parametrosInkjet->rotativa_cyan = $datosTipologias[0]->cyan;
            $parametrosInkjet->rotativa_magenta = $datosTipologias[0]->magenta;
            $parametrosInkjet->rotativa_amarillo = $datosTipologias[0]->amarillo;
            $parametrosInkjet->rotativa_cg = $datosTipologias[0]->cg;
        }

        $uso_tarifa = $uso;
        if ($uso == 'guardas')
            $uso_tarifa = 'interior';
        else if ($uso == 'faja')
            $uso_tarifa = 'sobrecubierta';
        $tarifamodel = new \App\Models\Configuracion\MaquinasTarifasImpresionModel();
        $datos_tarifa = $tarifamodel->getTarifa($maquina->maquina_id, $uso_tarifa, $tipo);
        if (count($datos_tarifa) > 0) {
            $tarifaId = $datos_tarifa[0];
            $tarifa = $datos_tarifa[1];
            $tarifa_margen = $datos_tarifa[2];
        } else {
            return [];
        }

        if ($maquina->is_inkjet) {
            $linea = PresupuestoService::getCostesLinea($uso, $datosPedido, $maquina, $papel, $opciones_papel, $tarifa, $tarifa_margen, $parametrosInkjet->a_favor_fibra);
        } else {
            $linea = PresupuestoService::getCostesLinea($uso, $datosPedido, $maquina, $papel, $opciones_papel, $tarifa, $tarifa_margen);
        }

        if (array_key_exists('error', $linea)) {
            //array_push($lineas, $linea); for debug
            return [];
        }

        if ($maquina->is_inkjet) {
            // calculo de tintas
            $linea['fields'] = array_merge($linea['fields'], PresupuestoService::calculoCosteTintas($maquina, $datosPedido, $parametrosInkjet));
        }

        $linea['fields']['tarifa_impresion_id'] = $tarifaId;
        $linea['fields']['maquina'] = $maquina->maquina;
        $linea['fields']['maquina_id'] = $maquina->maquina_id;
        $linea['fields']['maquina_velocidad'] = $maquina->velocidad;
        $linea['fields']['papel_impresion'] = $papel->nombre;
        $linea['fields']['papel_impresion_id'] = $papel->id;
        $linea['fields']['paginas'] = $datosPedido->paginas;
        $linea['fields']['gramaje'] = $gramaje;
        $linea['fields']['papel_generico_id'] = $papel_generico['id'];
        $linea['fields']['papel_generico'] = $papel_generico['nombre'];

        $linea['fields']['tiempo_maquina'] = PresupuestoService::getTiempoMaquina(
            $linea['fields']['precio_click_pedido'],
            $linea['fields']['precio_click'],
            $maquina->velocidad
        );

        $clientePreciosModel = new \App\Models\Clientes\ClientePreciosModel();
        $config = (object) [
            "tipo" => $uso_tarifa,
            "tipo_maquina" => $maquina->is_inkjet ? 'inkjet' : 'toner',
            "tipo_impresion" => $tipo
        ];
        $tiempo = PresupuestoService::getHorasMaquina(
            $linea['fields']['precio_click_pedido'],
            $linea['fields']['precio_click'],
            $maquina->velocidad
        );
        $tiempo = round($tiempo, 2);
        [$precio_hora, $margen_precio_hora] = $clientePreciosModel->get_precio_hora($cliente_id, $config, $tiempo);


        if (is_null($precio_hora)) {
            return [];
        }

        $linea['fields']['tipo_maquina'] = $maquina->is_inkjet ? 'inkjet' : 'toner';
        $linea['fields']['precio_hora'] = $precio_hora * (1 + $margen_precio_hora / 100.0);
        $linea['fields']['precio_hora_margen'] = $precio_hora * ($margen_precio_hora / 100.0);
        $linea['fields']['horas_maquina'] = $tiempo;
        $linea['fields']['precio_impresion_horas'] = $linea['fields']['precio_hora'] * $tiempo;
        $linea['fields']['margen_impresion_horas'] = $linea['fields']['precio_hora_margen'] * $tiempo;

        // para guardas
        if (\property_exists($datosPedido, 'paginas_impresion')) {
            $linea['fields']['paginas_impresion'] = $datosPedido->paginas_impresion;
        }

        if ($maquina->is_inkjet) {
            $linea['fields']['a_favor_fibra'] = $parametrosInkjet->a_favor_fibra;
            $linea['fields']['paginas_color'] = $isColor ? $datosPedido->paginas : 0;
            $linea['fields']['totalClicksPedido'] = $linea['fields']['precio_click_pedido'];
            if ($uso != 'guardas') {
                $linea['fields']['clicks_libro'] = round(ceil($linea['fields']['pliegos_libro']) * 2, 2);
            } else {
                if ($datosPedido->paginas_impresion == 4)
                    $linea['fields']['clicks_libro'] = round(ceil($linea['fields']['pliegos_libro']), 2);
                else if ($datosPedido->paginas_impresion == 8)
                    $linea['fields']['clicks_libro'] = round(ceil($linea['fields']['pliegos_libro']) * 2, 2);
                else
                    $linea['fields']['clicks_libro'] = 0;
            }
            $linea['fields']['clicks_pedido'] = round($linea['fields']['clicks_libro'] * ($datosPedido->tirada + $datosPedido->merma), 2);
            [$ancho, $alto] = PresupuestoService::calculoDimForma($datosPedido, $parametrosInkjet);
            $linea['fields']['factor_anchura'] = round($maquina->ancho_impresion / $ancho, 2);
            $linea['fields']['factor_altura'] = round($maquina->alto_impresion / ($alto + PresupuestoService::MARGEN_PAGINAS_ROTATIVA), 2);
            $linea['fields']['paginas_por_pliego'] = ($datosPedido->isCosido) ? $linea['fields']['num_formas']['value'] * 2 : $linea['fields']['num_formas']['value'] * 2; // Se multiplica *2 porque es doble cara
            $linea['fields']['datosTipologias'] = $datosTipologias[0];
            $linea['fields']['total_impresion'] =
                floatval($linea['fields']['precio_pedido']) + // papel
                floatval($linea['fields']['precio_impresion_horas']) +  // horas de maquina
                floatval($linea['fields']['precio_click_pedido']) + // precio clicks del pedido
                floatval($linea['fields']['precio_tinta']);  // tinta
        } else {
            $linea['fields']['total_impresion'] = floatval($linea['fields']['precio_pedido']) + // papel
                floatval($linea['fields']['precio_click_pedido']) + // precio clicks del pedido
                floatval($linea['fields']['precio_impresion_horas']);  // horas de maquina
        }


        return $linea;
    }


    public static function getLineaPresupuestoRotativa($data)
    {

        $uso = $data['uso'];
        $tipo = $data['tipo'];
        $datosPedido = $data['datosPedido'];
        $cliente_id = $data['cliente_id'];
        $papel = $data['papel'];
        $maquina = $data['maquina'];
        $papel_generico = $data['papel_generico'];
        $parametrosRotativa = $data['parametrosRotativa'];
        $gramaje = $data['gramaje'];
        $paginas = $data['paginas'];

        $tarifamodel = new MaquinasTarifasImpresionModel();

        $resultado_tarifa = $tarifamodel->getTarifa($maquina->maquina_id, $uso, is_array($tipo) ? 'color' : $tipo);
        if ($resultado_tarifa == null) {
            /*
            $info = [
                'maquina_id' => $maquina->maquina_id,
                'uso' => $uso,
                'tipo' => is_array($tipo) ? 'color' : $tipo
            ];
            log_message("error","No se ha encontrado tarifa para la maquina {maquina_id}  y el uso {uso} y el tipo {tipo}", $info);
            */
            return [];
        } else {
            $tarifaId = $resultado_tarifa[0];
            $tarifa = $resultado_tarifa[1];
            $tarifa_margen = $resultado_tarifa[2];
        }

        if (!is_float($tarifa)) {
            return [];
        }

        // precio del pliego de impresion
        $linea['fields'] = PresupuestoService::getCostesLineaRotativa($maquina, $papel, $datosPedido, $parametrosRotativa);
        if (count($linea['fields']) == 0) {
            return [];
        }

        $paginas_pedido = (intval($datosPedido->tirada) + intval($datosPedido->merma)) * intval($datosPedido->paginas);

        [$precio_pliego_impresion, $margen_pliego_impresion] = PresupuestoService::getPrecioPliego($maquina, $papel, $paginas_pedido);

        $linea['fields']['tarifa_impresion_id'] = $tarifaId;

        $linea['fields']['precios_pliegos'] = $precio_pliego_impresion + $margen_pliego_impresion;

        $linea['fields']['precio_libro'] = $linea['fields']['pliegos_libro'] * $linea['fields']['precios_pliegos'];
        // Precio papel pedido
        $linea['fields']['precio_pedido'] = $linea['fields']['precio_libro'] * ($datosPedido->tirada + $datosPedido->merma);
        $linea['fields']['margen_papel_pedido'] = $linea['fields']['pliegos_libro'] * $margen_pliego_impresion * ($datosPedido->tirada + $datosPedido->merma);
        ;

        $linea['fields']['a_favor_fibra'] = $parametrosRotativa->a_favor_fibra;
        $linea['fields']['maquina'] = $maquina->maquina;
        $linea['fields']['maquina_id'] = $maquina->maquina_id;
        $linea['fields']['maquina_velocidad'] = $maquina->velocidad;
        $linea['fields']['tipo_maquina'] = 'inkjet';
        $linea['fields']['papel_impresion'] = $papel->nombre;
        $linea['fields']['papel_impresion_id'] = $papel->id;
        $linea['fields']['paginas'] = $datosPedido->paginas;
        $linea['fields']['paginas_color'] = $paginas->color;
        $linea['fields']['gramaje'] = $gramaje;
        $linea['fields']['papel_generico_id'] = $papel_generico['id'];
        $linea['fields']['papel_generico'] = $papel_generico['nombre'];

        $linea['fields']['posicion_formas'] = $parametrosRotativa->a_favor_fibra ? 'h' : 'v';
        $linea['fields']['num_formas_horizontales'] = floor($linea['fields']['factor_anchura']);
        $linea['fields']['num_formas_verticales'] = floor($linea['fields']['factor_altura']);



        $linea['fields']['datosTipologias'] = //$datosTipologias[0];
            (object) array(
                'gota_negro' => $parametrosRotativa->rotativa_gota_negro,
                'gota_color' => $parametrosRotativa->rotativa_gota_color,
                'negro' => $parametrosRotativa->rotativa_negro,
                'cyan' => $parametrosRotativa->rotativa_cyan,
                'magenta' => $parametrosRotativa->rotativa_magenta,
                'amarillo' => $parametrosRotativa->rotativa_amarillo
            );

        // impresion
        $linea['fields']['precio_click'] = $tarifa * (1 + $tarifa_margen / 100.0);
        $linea['fields']['precio_click_margen'] = $tarifa * ($tarifa_margen / 100.0);
        $linea['fields']['precio_click_pedido'] = $linea['fields']['clicks_pedido'] * $linea['fields']['precio_click'];
        $linea['fields']['margen_click_pedido'] = $linea['fields']['clicks_pedido'] * $linea['fields']['precio_click_margen'];

        $linea['fields']['tiempo_maquina'] = PresupuestoService::getTiempoMaquina(
            $linea['fields']['precio_click_pedido'],
            $linea['fields']['precio_click'],
            $maquina->velocidad
        );


        $clientePreciosModel = new ClientePreciosModel();
        $config = (object) [
            "tipo" => $uso,
            "tipo_maquina" => 'inkjet',
            "tipo_impresion" => $tipo
        ];
        $tiempo = PresupuestoService::getHorasMaquina(
            $linea['fields']['precio_click_pedido'],
            $linea['fields']['precio_click'],
            $maquina->velocidad
        );
        [$precio_hora, $margen_precio_hora] = $clientePreciosModel->get_precio_hora($cliente_id, $config, $tiempo);

        if (is_null($precio_hora)) {
            return [];
        }

        $linea['fields']['precio_hora'] = $precio_hora * (1 + $margen_precio_hora / 100.0);
        $linea['fields']['precio_hora_margen'] = $precio_hora * ($margen_precio_hora / 100.0);
        $linea['fields']['horas_maquina'] = $tiempo;
        $linea['fields']['precio_impresion_horas'] = $linea['fields']['precio_hora'] * $tiempo;
        $linea['fields']['margen_impresion_horas'] = $linea['fields']['precio_hora_margen'] * $tiempo;

        // total linea rotativa
        //$linea['fields']['total_impresion'] = $linea['fields']['precio_pedido'] + $linea['fields']['precio_click_pedido'] + $linea['fields']['precio_tinta'] + 
        //                $linea['fields']['total_corte'];
        $linea['fields']['total_impresion'] =
            floatval($linea['fields']['precio_pedido']) + // papel
            floatval($linea['fields']['precio_click_pedido']) + // precio clicks del pedido
            floatval($linea['fields']['precio_impresion_horas']) +   // horas de maquina
            floatval($linea['fields']['precio_tinta']) +   // tinta
            floatval($linea['fields']['total_corte']);    // corte

        return $linea;
    }


    public static function getCostesLinea($uso, $datosPedido, $maquina, $papel_impresion, $opciones_papel, $tarifa, $tarifa_margen, $forzar_a_favor_fibra = false)
    {
        $response['fields'] = [];

        if ($uso != 'rotativa') {

            $ancho_calculo = ($uso == 'cubierta' || $uso == 'sobrecubierta' || $uso == 'faja') ? $datosPedido->anchoExteriores : $datosPedido->ancho;
            $alto_calculo = ($uso == 'cubierta' || $uso == 'sobrecubierta' || $uso == 'faja') ? $datosPedido->altoExteriores : $datosPedido->alto;
            $formas = PresupuestoService::getNumFormasPlana($uso, $maquina, $ancho_calculo, $alto_calculo, $datosPedido->isCosido, $forzar_a_favor_fibra);
            $response['fields'] = $formas;
        }


        if ($response['fields']['num_formas']['posicion_formas'] == 'n/a') {
            $response['error']['value'] = true;
            $response['error']['message'] = 'no_formas_disponibles';
            return $response;
        }

        $paginas_pedido = (intval($datosPedido->tirada) + intval($datosPedido->merma)) * intval($datosPedido->paginas);

        // precio del pliego de impresion
        [$precio_pliego_impresion, $margen_pliego_impresion] = PresupuestoService::getPrecioPliego($maquina, $papel_impresion, $paginas_pedido);

        $precio_click = 0;
        $precio_click_pedido = 0;
        $margen_click_pedido = 0;
        $pliegos_libro = 0;

        $cubierta = array_key_exists('cubierta', $opciones_papel) ? $opciones_papel['cubierta'] : 0;
        $sobrecubierta = array_key_exists('sobrecubierta', $opciones_papel) ? $opciones_papel['sobrecubierta'] : 0;
        $rotativa = array_key_exists('rotativa', $opciones_papel) ? $opciones_papel['rotativa'] : 0;


        $precio_click = $tarifa * (1 + $tarifa_margen / 100.0);
        $margen_click = $tarifa * ($tarifa_margen / 100.0);

        //interior (bn o color)
        if ($cubierta == 0 && $sobrecubierta == 0 && $rotativa == 0 || $uso == 'faja') {
            // precio papel
            $pliegos_libro = ($datosPedido->paginas / 2.0) / $response['fields']['num_formas']['value'];
            if ($uso != 'faja')
                $pliegos_libro = ceil($pliegos_libro);
            if ($uso != 'faja' && $pliegos_libro < 1) // faja pueden entrar más de una forma
                $pliegos_libro = 1;
            $pliegos_pedido = $pliegos_libro * ($datosPedido->tirada + $datosPedido->merma);
            $precio_libro = $pliegos_libro * ($precio_pliego_impresion + $margen_pliego_impresion);
            $margen_papel_pedido = $pliegos_libro * $margen_pliego_impresion * ($datosPedido->tirada + $datosPedido->merma);
            $precio_pedido = $precio_libro * ($datosPedido->tirada + $datosPedido->merma);

            $mano = PresupuestoService::computeLomoInterior($datosPedido->paginas, $papel_impresion->espesor);

            // peso
            $peso = PresupuestoService::computePeso(
                ancho: $datosPedido->isCosido ? $datosPedido->ancho / 2.0 : $datosPedido->ancho,
                alto: $datosPedido->alto,
                gramaje: $papel_impresion->gramaje,
                paginas: $datosPedido->paginas
            );

            // impresion
            if ($uso == 'guardas') {
                if (floatval($datosPedido->paginas_impresion) == 0)
                    $precio_click_pedido = 0;
                elseif (floatval($datosPedido->paginas_impresion) == 4) { // Una cara
                    $precio_click_pedido = $pliegos_pedido * $precio_click;
                    $margen_click_pedido = $pliegos_pedido * $margen_click;
                } else { // dos caras (impresion normal)
                    $precio_click_pedido = $pliegos_pedido * 2 * $precio_click;
                    $margen_click_pedido = $pliegos_pedido * 2 * $margen_click;
                }
            } else {
                $precio_click_pedido = $pliegos_pedido * 2 * $precio_click;
                $margen_click_pedido = $pliegos_pedido * 2 * $margen_click;
            }
        }
        // cubierta o sobrecubierta (siempre a color)
        else if (($cubierta == 1 || $sobrecubierta == 1) && $rotativa == 0) {
            // precio papel
            $pliegos_libro = 1.0 / $response['fields']['num_formas']['value'];
            // En cubierta y sobrecubierta siempre el mínimo pliego es 1
            $pliegos_libro = $pliegos_libro < 1 ? 1 : $pliegos_libro;
            $pliegos_pedido = $pliegos_libro * ($datosPedido->tirada + $datosPedido->merma);
            $precio_libro = $pliegos_libro * ($precio_pliego_impresion + $margen_pliego_impresion);
            $margen_papel_pedido = $pliegos_libro * $margen_pliego_impresion * ($datosPedido->tirada + $datosPedido->merma);
            $precio_pedido = $precio_libro * ($datosPedido->tirada + $datosPedido->merma);

            $mano = PresupuestoService::computeLomoPortada($papel_impresion->espesor);

            // peso
            $ancho_total = $datosPedido->anchoExteriores + $mano;
            $peso = PresupuestoService::computePeso($ancho_total, $datosPedido->alto, $papel_impresion->gramaje);

            // impresion
            if ($tarifa) {
                $precio_click_pedido = $pliegos_pedido * $precio_click;
                $margen_click_pedido = $pliegos_pedido * $margen_click;

                // dos caras
                if ($datosPedido->paginas > 2) {
                    $precio_click_pedido *= 2.0;
                    $margen_click_pedido *= 2.0;
                }
            }
        }


        // response
        $response['fields']['pliegos_libro'] = $pliegos_libro;
        $response['fields']['pliegos_pedido'] = $pliegos_pedido;
        $response['fields']['precios_pliegos'] = $precio_pliego_impresion + $margen_pliego_impresion;
        $response['fields']['precio_libro'] = $precio_libro;
        $response['fields']['margen_papel_pedido'] = $margen_papel_pedido;
        $response['fields']['precio_pedido'] = $precio_pedido;
        $response['fields']['mano'] = $mano;
        $response['fields']['peso'] = $peso;
        $response['fields']['precio_click'] = $precio_click;
        $response['fields']['precio_click_pedido'] = $precio_click_pedido;
        $response['fields']['margen_click_pedido'] = $margen_click_pedido;

        $response['fields']['dimensiones_maquina'] = [$maquina->ancho, $maquina->alto];
        $response['fields']['dimensiones_maquina_impresion'] = [$maquina->ancho_impresion, $maquina->alto_impresion];
        $response['fields']['dimensiones_maquina_click'] = [$maquina->ancho_impresion, $maquina->alto_click];
        $response['fields']['dimensiones_libro'] = [$datosPedido->ancho, $datosPedido->alto];

        return $response;
    }



    /**
     * Devuelve los calculos para la linea de rotativa.
     */
    public static function getCostesLineaRotativa($maquina, $papel_impresion, $datosPedido, $parametrosRotativa)
    {
        $data = [];

        [$data['ancho'], $data['alto']] = PresupuestoService::calculoDimForma($datosPedido, $parametrosRotativa);

        // calculo de papel y clicks
        $factor_anchura = floor($maquina->ancho_impresion / $data['ancho']);
        $factor_altura = round($maquina->alto_impresion / ($data['alto'] + self::MARGEN_PAGINAS_ROTATIVA), 2);
        $factor_altura_click = round($maquina->alto_click / ($data['alto'] + self::MARGEN_PAGINAS_ROTATIVA), 2);

        if (floor($factor_anchura) == 0) {
            return [];
        }

        $multiplicador_pliego = $datosPedido->isCosido ? 4 : 2;
        $paginas_por_pliego = round($factor_anchura * $factor_altura * $multiplicador_pliego, 2);
        $pliegos_libro = round($paginas_por_pliego ? $datosPedido->paginas / $paginas_por_pliego : 0, 2);
        $metros_papel_libro = round($pliegos_libro * ($maquina->alto_impresion / 1000.0), 2);
        $metros_papel_total = round($metros_papel_libro * ($datosPedido->tirada + $datosPedido->merma), 2);

        $paginas_por_pliego_click = round($factor_anchura * $factor_altura_click * $multiplicador_pliego, 2);
        $pliegos_libro_click = round($paginas_por_pliego_click ? $datosPedido->paginas / $paginas_por_pliego_click : 0, 2);
        $clicks_libro = round(ceil($pliegos_libro_click) * 2, 2);
        $clicks_pedido = round($clicks_libro * ($datosPedido->tirada + $datosPedido->merma), 2);

        $data['factor_altura'] = $factor_altura;
        $data['factor_anchura'] = $factor_anchura;
        $data['paginas_por_pliego'] = $paginas_por_pliego;
        $data['pliegos_libro'] = $pliegos_libro;
        $data['pliegos_pedido'] = $pliegos_libro * ($datosPedido->tirada + $datosPedido->merma);
        $data['metros_papel_libro'] = $metros_papel_libro;
        $data['metros_papel_total'] = $metros_papel_total;
        $data['clicks_libro'] = $clicks_libro;
        $data['clicks_pedido'] = $clicks_pedido;

        // calculo de tintas
        $data = array_merge($data, PresupuestoService::calculoCosteTintas($maquina, $datosPedido, $parametrosRotativa));

        // calculo de corte
        $data['velocidad_corte'] = $maquina->velocidad_corte;
        $data['precio_hora_corte'] = $maquina->precio_hora_corte;
        $data['tiempo_corte'] = $maquina->velocidad_corte > 0 ? round($metros_papel_total / $maquina->velocidad_corte, 2) : 0;
        $data['total_corte'] = round(($data['tiempo_corte'] / 60.0) * $maquina->precio_hora_corte, 2);

        $data['mano'] = PresupuestoService::computeLomoInterior($datosPedido->paginas, $papel_impresion->espesor);
        // ($paginas / 2.0) * (($gramaje / 1000.0) * $papel_compra->mano);

        // peso
        $data['peso'] = PresupuestoService::computePeso(
            ancho: $datosPedido->isCosido ? $datosPedido->ancho / 2.0 : $datosPedido->ancho,
            alto: $datosPedido->alto,
            gramaje: $papel_impresion->gramaje,
            paginas: $datosPedido->paginas
        );

        $data['dimensiones_maquina'] = [$maquina->ancho, $maquina->alto];
        $data['dimensiones_maquina_impresion'] = [$maquina->ancho_impresion, $maquina->alto_impresion];
        $data['dimensiones_maquina_click'] = [$maquina->ancho_impresion, $maquina->alto_click];
        $data['dimensiones_libro'] = [$datosPedido->ancho, $datosPedido->alto];

        $data['alto_click'] = $maquina->alto_click;

        $direccion_fibra = ($parametrosRotativa->a_favor_fibra === "false" || $parametrosRotativa->a_favor_fibra === 0 ||
            $parametrosRotativa->a_favor_fibra === "0" || $parametrosRotativa->a_favor_fibra === false) ? 0 : 1;

        $formas = PresupuestoService::getNumFormasRot(
            $maquina,
            $datosPedido->ancho,
            $datosPedido->alto,
            $datosPedido->isCosido,
            $direccion_fibra
        );
        $data['num_formas'] = $formas;

        return $data;
    }


    /**
     * Devuelve los calculos de las dimensiones de la forma
     */
    public static function calculoDimForma($datosPedido, $parametros)
    {
        // posicionamos paginas en función de a favor de fibra o no
        if ($parametros->a_favor_fibra === "false" || $parametros->a_favor_fibra === 0 || $parametros->a_favor_fibra === "0" || $parametros->a_favor_fibra === false) {
            $anchoLibro = $datosPedido->alto;
            $altoLibro = $datosPedido->ancho;
        } else {
            $anchoLibro = $datosPedido->ancho;
            $altoLibro = $datosPedido->alto;
        }

        // si es cosido ancho x 2
        if ($datosPedido->isCosido) {
            if ($parametros->a_favor_fibra === "false" || $parametros->a_favor_fibra === 0 || $parametros->a_favor_fibra === "0" || $parametros->a_favor_fibra === false) {
                $altoLibro = $altoLibro * 2;
            } else {
                $anchoLibro = $anchoLibro * 2;
            }
        }

        return [$anchoLibro, $altoLibro];
    }


    /**
     * Devuelve los calculos para el coste de tintas
     */
    public static function calculoCosteTintas($maquina, $datosPedido, $parametros)
    {
        $data = [];

        $data['pulgada'] = 1 / 1000000000000.0;
        if ($maquina->maquina_id == 91 || $maquina->maquina_id == 99 || $maquina->maquina_id == 114 || $maquina->maquina_id == 98)
            $data['resolucion'] = 1200;
        else
            $data['resolucion'] = 600;
        $data['superficie'] = round((($datosPedido->ancho / 2.54) / 10) * (($datosPedido->alto / 2.54) / 10), 2);

        $data['num_gotas_negro'] = round($data['superficie'] * $data['resolucion'] * $data['resolucion'] * ($parametros->rotativa_negro / 100.0), 0);
        $data['num_gotas_cyan'] = round($data['superficie'] * $data['resolucion'] * $data['resolucion'] * ($parametros->rotativa_cyan / 100.0), 0);
        $data['num_gotas_magenta'] = round($data['superficie'] * $data['resolucion'] * $data['resolucion'] * ($parametros->rotativa_magenta / 100.0), 0);
        $data['num_gotas_amarillo'] = round($data['superficie'] * $data['resolucion'] * $data['resolucion'] * ($parametros->rotativa_amarillo / 100.0), 0);

        $pag_negro = $parametros->bnPages;
        $pag_color = 0;
        if ($parametros->colorPages > 0) {
            $pag_color = $parametros->colorPages;
        }

        // peso tintas
        $data['peso_gotas_negro'] = round((($data['num_gotas_negro'] * $parametros->rotativa_gota_negro * $data['pulgada']) / (17.91 / 20.0)) * $pag_negro * 1000, 6);
        $data['peso_gotas_negro'] += round((($data['num_gotas_negro'] * $parametros->rotativa_gota_negro * $data['pulgada']) / (17.91 / 20.0)) * $pag_color * 1000, 6);
        $data['peso_gotas_cyan'] = round((($data['num_gotas_cyan'] * $parametros->rotativa_gota_color * $data['pulgada']) / (17.65 / 20.0)) * $pag_color * 1000, 6);
        $data['peso_gotas_magenta'] = round((($data['num_gotas_magenta'] * $parametros->rotativa_gota_color * $data['pulgada']) / (17.65 / 20.0)) * $pag_color * 1000, 6);
        $data['peso_gotas_amarillo'] = round((($data['num_gotas_amarillo'] * $parametros->rotativa_gota_color * $data['pulgada']) / (17.65 / 20.0)) * $pag_color * 1000, 6);

        // costes de tintas
        $data['peso_gotas_negro_pedido'] = round($data['peso_gotas_negro'], 2) * ($datosPedido->tirada + $datosPedido->merma);
        $data['peso_gotas_cyan_pedido'] = round($data['peso_gotas_cyan'], 2) * ($datosPedido->tirada + $datosPedido->merma);
        $data['peso_gotas_magenta_pedido'] = round($data['peso_gotas_magenta'], 2) * ($datosPedido->tirada + $datosPedido->merma);
        $data['peso_gotas_amarillo_pedido'] = round($data['peso_gotas_amarillo'], 2) * ($datosPedido->tirada + $datosPedido->merma);

        // precio tinta
        $data['precio_tinta'] = round(
            round(($data['peso_gotas_negro_pedido'] / 1000.0) * $maquina->precio_tinta_negro, 2) +
            round(($data['peso_gotas_cyan_pedido'] / 1000.0) * $maquina->precio_tinta_color, 2) +
            round(($data['peso_gotas_magenta_pedido'] / 1000.0) * $maquina->precio_tinta_color, 2) +
            round(($data['peso_gotas_amarillo_pedido'] / 1000.0) * $maquina->precio_tinta_color, 2),
            2
        );


        if ($maquina->is_inkjet) {
            $data['num_gotas_cg'] = round($data['superficie'] * $data['resolucion'] * $data['resolucion'] * ($parametros->rotativa_cg / 100.0), 0);
            $data['peso_gotas_cg'] = round((($data['num_gotas_cg'] * $parametros->rotativa_gota_color * $data['pulgada']) / (17.65 / 20.0)) * $pag_color * 1000, 6) +
                round((($data['num_gotas_cg'] * $parametros->rotativa_gota_negro * $data['pulgada']) / (17.65 / 20.0)) * $pag_negro * 1000, 6);
            $data['peso_gotas_cg_pedido'] = round($data['peso_gotas_cg'], 2) * ($datosPedido->tirada + $datosPedido->merma);

            $data['precio_tinta'] += round(($data['peso_gotas_cg_pedido'] / 1000.0) * $maquina->precio_tinta_cg, 2);
        }

        // precio pagina
        $data['precio_pagina_negro'] = round($pag_negro ? $data['precio_tinta'] / ($pag_negro * ($datosPedido->tirada + $datosPedido->merma)) : 0, 6);
        $data['precio_pagina_color'] = round($pag_color ? $data['precio_tinta'] / ($pag_color * ($datosPedido->tirada + $datosPedido->merma)) : 0, 6);

        return $data;
    }


    public static function getNumFormasRot($maquina, $ancho, $alto, $isCosido, $a_favor_fibra = true)
    {
        // El ancho si es cosido es el doble
        $anchoForCalculo = $isCosido ? $ancho * 2 : $ancho;

        $altoForCalculo = $alto;

        $h1_temp = floor($maquina->ancho_impresion / $anchoForCalculo);
        $h2_temp = floor($maquina->ancho_impresion / $altoForCalculo);

        // horizontales
        if ($a_favor_fibra) {

            $calles = (new \App\Models\Configuracion\MaquinasCallesModel())->getCallesForMaquina($maquina->maquina_id, $h1_temp);
            // Si son mas de 2 formas
            if (count($calles) > 0)
                $h1 = ($h1_temp * $anchoForCalculo + 2 * $calles[0]->externas + ($h1_temp - 1) * $calles[0]->internas < (floatval($maquina->ancho))) ? $h1_temp : $h1_temp - 1;
            else
                $h1 = $h1_temp;

            $v1 = floor(floatval($maquina->alto_click) / $altoForCalculo);
            $formas_h = $h1 * $v1; //p1
        }
        // verticales
        else {

            $calles = (new \App\Models\Configuracion\MaquinasCallesModel())->getCallesForMaquina($maquina->maquina_id, $h2_temp);
            if (count($calles) > 0)
                $h2 = ($h2_temp * $altoForCalculo + 2 * $calles[0]->externas + ($h2_temp - 1) * $calles[0]->internas < (floatval($maquina->ancho))) ? $h2_temp : $h2_temp - 1;
            else
                $h2 = $h2_temp;
            $v2 = floor(floatval($maquina->alto_click) / $anchoForCalculo);
            $formas_v = $h2 * $v2; //p2
        }

        $num_formas = $a_favor_fibra ? $formas_h : $formas_v;
        $num_formas = $isCosido ? $num_formas * 2 : $num_formas;


        // si no hay formas se devuelve n/a 
        if ($num_formas == 0) {
            $response['posicion_formas'] = 'n/a'; // not available
        } else if ($a_favor_fibra) {
            $response['posicion_formas'] = 'h';
            $response['num_formas_horizontales'] = $h1;
            $response['num_formas_verticales'] = $v1;
            $response['value'] = $num_formas;
        } else {
            $response['posicion_formas'] = 'v';
            $response['num_formas_horizontales'] = $h2;
            $response['num_formas_verticales'] = $v2;
            $response['value'] = $num_formas;
        }

        return $response;
    }

    public static function getNumFormasPlana($uso, $maquina, $ancho, $alto, $isCosido, $forzar_a_favor_fibra = false)
    {
        $h1_temp = 0;
        $h2_temp = 0;

        // El ancho si es cosido es el doble
        if ($uso != 'cubierta' && $uso != 'sobrecubierta' && $uso != 'faja') {
            $anchoForCalculo = $isCosido ? $ancho * 2 : $ancho;
        } else {
            $anchoForCalculo = $ancho;
        }

        $altoForCalculo = $alto;

        if ($uso == 'cubierta' || $uso == 'sobrecubierta') {
            if (
                !is_null($maquina->forzar_num_formas_horizontales_cubierta) &&
                !is_null($maquina->forzar_num_formas_verticales_cubierta)

            ) {

                if (
                    $maquina->forzar_num_formas_horizontales_cubierta > 0 &&
                    $maquina->forzar_num_formas_verticales_cubierta > 0
                ) {

                    // Hay que comprobar que entran
                    $h1_temp = $maquina->forzar_num_formas_horizontales_cubierta;
                    $h2_temp = $maquina->forzar_num_formas_verticales_cubierta;
                    //$num_formas = $h1_temp * $h2_temp;
                }
            }
        }
        // No es cubierta ni sobrecubierta
        else {
            // horizontales
            if ($uso == 'faja') {
                $h1_temp = 1;
            } else {

                $h1_temp = floor(floatval($maquina->ancho_impresion) / $anchoForCalculo);
            }
            $h2_temp = floor(floatval($maquina->ancho_impresion) / $altoForCalculo);
        }

        // horizontales
        $calles = (new \App\Models\Configuracion\MaquinasCallesModel())->getCallesForMaquina($maquina->maquina_id, $h1_temp);
        // Si son mas de 2 formas
        if (count($calles) > 0)
            $h1 = ($h1_temp * $anchoForCalculo + 2 * $calles[0]->externas + ($h1_temp - 1) * $calles[0]->internas < ($maquina->ancho)) ? $h1_temp : $h1_temp - 1;
        else {
            $h1 = $anchoForCalculo <= $maquina->ancho_impresion ? $h1_temp : 0;
        }


        $v1 = floor($maquina->alto_impresion / $altoForCalculo);
        $formas_h = $h1 * $v1; //p1

        // verticales
        $calles = (new \App\Models\Configuracion\MaquinasCallesModel())->getCallesForMaquina($maquina->maquina_id, $h2_temp);
        if (count($calles) > 0)
            $h2 = ($h2_temp * $altoForCalculo + 2 * $calles[0]->externas + ($h2_temp - 1) * $calles[0]->internas < ($maquina->ancho)) ? $h2_temp : $h2_temp - 1;
        else {
            $h2 = $altoForCalculo <= $maquina->ancho_impresion ? $h2_temp : 0;
        }

        $v2 = floor($maquina->alto_impresion / $anchoForCalculo);
        $formas_v = $h2 * $v2; //p2


        // Se calcula el numero de formas
        if ($uso != 'cubierta' && $uso != 'sobrecubierta' && !$forzar_a_favor_fibra) {
            $num_formas = ($formas_h > $formas_v) ? $formas_h : $formas_v;
            $num_formas = $isCosido ? $num_formas * 2 : $num_formas;
        } else if ($forzar_a_favor_fibra) {

            $num_formas = $formas_h;
            $num_formas = $isCosido ? $num_formas * 2 : $num_formas;
        } else {

            $num_formas = $h1 * $v1;
        }


        // si no hay formas se devuelve n/a 
        if ($num_formas == 0) {
            $response['num_formas']['posicion_formas'] = 'n/a'; // not available
        } else {
            if ($formas_h > $formas_v || $forzar_a_favor_fibra && $formas_h != 0) {
                $response['num_formas']['posicion_formas'] = 'h';
                $response['num_formas']['num_formas_horizontales'] = $h1;
                $response['num_formas']['num_formas_verticales'] = $v1;
                $response['num_formas']['value'] = $num_formas;
            } else {
                if ($formas_v != 0) {
                    $response['num_formas']['posicion_formas'] = 'v';
                    $response['num_formas']['num_formas_horizontales'] = $h2;
                    $response['num_formas']['num_formas_verticales'] = $v2;
                    $response['num_formas']['value'] = $num_formas;
                }
            }

            if (($uso == 'cubierta' || $uso == 'sobrecubierta') && $num_formas > 0) {
                if (
                    property_exists($maquina, 'forzar_num_formas_horizontales_cubierta') &&
                    property_exists($maquina, 'forzar_num_formas_horizontales_cubierta')
                ) {
                    $response['num_formas']['num_formas_verticales'] = $h2_temp;
                }
            }
        }

        return $response;
    }


    public static function getPrecioPliego($maquina, $papel_impresion, $paginas)
    {
        $margen = (new \App\Models\Configuracion\PapelImpresionMargenModel())->getMargenFormPags($papel_impresion->id, $paginas);
        if (count($margen) > 0) {
            $peso_por_pliego = $maquina->alto * $maquina->ancho * $papel_impresion->gramaje / 1000000;
            $precio_pliego = ($peso_por_pliego * $papel_impresion->precio_tonelada / 1000000.0);
            $margen_pliego = ($peso_por_pliego * $papel_impresion->precio_tonelada / 1000000.0) * (floatval($margen[0]['margen']) / 100.0);
            return [round($precio_pliego, 6), round($margen_pliego, 6)];
        }
        return -1;
    }

    public static function getTiempoMaquina($totalClicks, $precioClick, $velocidadMaquina)
    {
        try {

            if (floatval($precioClick) > 0 && floatval($velocidadMaquina) > 0)
                $minutos = (1.0 * floatval($totalClicks) / floatval($precioClick)) / floatval($velocidadMaquina);
            else
                $minutos = 0;

            return gmdate("H:i:s", round($minutos * 60, 0));
        } catch (Exception $e) {
            return gmdate("H:i:s", round(0, 0));
        }
    }

    public static function getHorasMaquina($totalClicks, $precioClick, $velocidadMaquina)
    {
        try {

            if (floatval($precioClick) > 0 && floatval($velocidadMaquina) > 0)
                $horas = (1.0 * floatval($totalClicks) / floatval($precioClick)) / floatval($velocidadMaquina) / 60.0;
            else
                $horas = 0;

            return $horas;
        } catch (Exception $e) {
            return 0;
        }
    }


    /**
     * Devuelve el ancho de la cubierta/sobrecubierta, incluido el lomo.
     *  El $uso tiene que ser "cubierta" o "sobrecubierta"
     */
    public static function getAnchoTotalExteriores($uso = "cubierta", $tipo_impresion_id = 1, $datosPedido = null, $maquina_id = -1, $lomoRedondo = 0)
    {
        $ancho_total = 0;
        $sangre_cubierta = self::SANGRE_FORMAS_CUBIERTA;
        if ($datosPedido->ancho >= 210) {
            $sangre_cubierta = 10;
        }

        if ($datosPedido) {
            // Tapa blanda (cosido y fresado)
            if ($tipo_impresion_id == 2 || $tipo_impresion_id == 4) {
                $ancho_total = floatval($datosPedido->ancho) * 2 + floatval($datosPedido->lomo);

                // añadimos ancho de las solapas
                // si se añaden solapas hay que sumar 3mm de los dobleces
                if ($datosPedido->solapas) {
                    $ancho_total += (floatval($datosPedido->solapas_ancho) * 2) + 6;
                }
                // Se le suma 5mm de sangre por cada lado
                $ancho_total += (2 * self::SANGRE_FORMAS);
            }
            // Tapa dura cosido y fresado
            else if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3) {
                $ancho_total = floatval($datosPedido->ancho) * 2 + floatval($datosPedido->lomo);
                // si es cubierta
                // se añade 7mm del ancho del cartón (2*3.5mm) por cada lado del lomo
                // más 7mm de vuelo+cajo por cada lado. Por último, 20mm de sangre por cada lado
                if ($uso == "cubierta") {
                    $ancho_total += (2 * 7 + 2 * $sangre_cubierta + 6);
                    if ($lomoRedondo) {
                        $ancho_total += 6;
                    }
                } else if ($uso == 'faja' || $uso == 'sobrecubierta') {
                    if ($datosPedido->solapas) {
                        // 7 es el vuelo de la tapa dura sobre el interior
                        $ancho_total += (floatval($datosPedido->solapas_ancho) * 2) + (2 * self::SANGRE_FORMAS) + 2 * 7;
                    }
                }

                // si es sobrecubierta
                // Se añaden 5mm de sangre por cada lado + 2 * 7mm de vuelo portada y contraportada -> total 52
                else {
                    $ancho_total += (2 * 7 + 2 * self::SANGRE_FORMAS);
                }
            }
            // Wire-o y espiral (tapa blanda y tapa dura)
            else if (
                $tipo_impresion_id == 5 || $tipo_impresion_id == 6 ||
                $tipo_impresion_id == 7 || $tipo_impresion_id == 8
            ) {
                // En este caso, la cubierta se imprime como dos formas separadas, pero hay que dejar un 
                // espacio entre ellas para poder cortarlas
                $calles = (new \App\Models\Configuracion\MaquinasCallesModel())->getCallesForMaquina($maquina_id, 2);
                $ancho_total = floatval($datosPedido->ancho) * 2;

                if (count($calles) > 0)
                    $ancho_total += $calles[0]->internas;

                // Tapa blanda
                if ($tipo_impresion_id == 7 || $tipo_impresion_id == 8) {
                    // añadimos ancho de las solapas
                    // si se añaden solapas hay que sumar 3mm de los dobleces
                    if ($datosPedido->solapas) {
                        $ancho_total += (floatval($datosPedido->solapas_ancho) * 2) + 6;
                    }

                    // Se le suma 5mm de sangre por cada lado. Como son 2 hojas independientes, se multiplica por 4
                    $ancho_total += (4 * self::SANGRE_FORMAS);
                }
                // Tapa dura
                else {
                    // Se le suma 20mm de sangre por cada lado. Como son 2 hojas independientes, se multiplica por 4
                    $ancho_total += (4 * $sangre_cubierta);
                }
            } else {
                // En cualquier otro caso se le suma 5mm de sangre por cada lado
                $ancho_total += (2 * self::SANGRE_FORMAS);
            }
        }
        return $ancho_total;
    }

    /**
     * Devuelve el alto de la cubierta/sobrecubierta
     */
    public static function getAltoTotalExteriores($uso = "cubierta", $tipo_impresion_id = 1, $datosPedido = null)
    {
        $alto_total = 0;

        if ($datosPedido) {
            $alto_total = floatval($datosPedido->alto);
            $sangre_cubierta = self::SANGRE_FORMAS_CUBIERTA;
            if ($datosPedido->alto >= 267) {
                $sangre_cubierta = 10;
            }
            // Tapa dura (cosido y fresado)
            if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3) {
                // Se añaden 20mm de sangre por cada lado + 3.5mm extra por cada lado de vuelo
                if ($uso == "cubierta")
                    $alto_total += (2 * 3.5 + 2 * $sangre_cubierta);
                // si es sobrecubierta
                // Se añaden 5mm de sangre por cada lado
                else if ($uso == 'sobrecubierta')
                    $alto_total += (7 + 2 * self::SANGRE_FORMAS);
                else if ($uso == 'faja')
                    $alto_total += (2 * self::SANGRE_FORMAS);
            }
            // Tapa dura (espiral y wire-0)
            else if ($tipo_impresion_id == 5 || $tipo_impresion_id == 7) {
                // Sólo se le añade los 20mm de sangre por cada lado
                $alto_total += (2 * self::SANGRE_FORMAS_CUBIERTA);
            }
            // En cualquier otro caso se le suma 5mm de sangre por cada lado
            else {
                $alto_total += (2 * self::SANGRE_FORMAS);
            }
        }
        return $alto_total;
    }


    public static function get_opciones_papel($uso, $isColor)
    {

        $opciones_papel = [];

        if ($uso == 'cubierta') {
            $opciones_papel = array(
                'cubierta' => 1,
                //'color' => 1,
                'rotativa' => 0,
            );
        } else if ($uso == 'sobrecubierta' || $uso == 'faja') {
            $opciones_papel = array(
                'sobrecubierta' => 1,
                //'color' => 1,
                'rotativa' => 0,
            );
        } else if ($uso == 'guardas') {
            $opciones_papel = array(
                'guardas' => 1,
                //'color' => 1,
                'rotativa' => 0,
            );
        } else if ($isColor) {
            $opciones_papel = array(
                'color' => 1,
                'rotativa' => 0,
            );
        } else {
            $opciones_papel = array(
                'bn' => 1,
                'rotativa' => 0,
            );
        }

        return $opciones_papel;
    }


    public static function actualizarResumenPresupuesto($presupuesto_id)
    {
        $presupuesto = (new PresupuestoModel())->find($presupuesto_id);
        $lineas = (new LineaPresupuestoModel())->where('presupuesto_id', $presupuesto_id)->findAll();
    }

    public static function checkLineasPresupuesto($input_data, $array_lineas)
    {

        $data['tipo_impresion_id'] = ($input_data['presupuesto'])->tipo_impresion_id;
        $data['tirada'] = ($input_data['presupuesto'])->tirada;
        $data['merma'] = ($input_data['presupuesto'])->merma;
        $data['papel_formato_id'] = ($input_data['presupuesto'])->papel_formato_id;
        $data['papel_formato_personalizado'] = ($input_data['presupuesto'])->papel_formato_personalizado;
        $data['papel_formato_ancho'] = ($input_data['presupuesto'])->papel_formato_ancho;
        $data['papel_formato_alto'] = ($input_data['presupuesto'])->papel_formato_alto;
        $data['cliente_id'] = ($input_data['presupuesto'])->cliente_id;
        $data['solapas'] = ($input_data['presupuesto'])->solapas;
        $data['solapas_ancho'] = ($input_data['presupuesto'])->solapas_ancho;
        $data['solapas_sobrecubierta'] = ($input_data['presupuesto'])->solapas_sobrecubierta;
        $data['solapas_ancho_sobrecubierta'] = ($input_data['presupuesto'])->solapas_ancho_sobrecubierta;
        $data['lomo_cubierta'] = ($input_data['presupuesto'])->lomo_cubierta;
        $data['lomo_sobrecubierta'] = ($input_data['presupuesto'])->lomo_sobrecubierta;

        $cambios = false;

        $lineas = [];

        foreach ($array_lineas as $linea) {

            // Si el papel o la máquina no existen, se utiliza la más barata del comparador
            if (!PresupuestoService::checkMaquina($linea->maquina_id) || !PresupuestoService::checkPapelImpresion($linea->papel_impresion_id)) {

                if (($input_data['presupuesto'])->papel_formato_personalizado == 0) {
                    $papel_formato = (new PapelFormatoModel())->find(($input_data['presupuesto'])->papel_formato_id);
                    $ancho = $papel_formato->ancho;
                    $alto = $papel_formato->alto;
                } else {
                    $ancho = ($input_data['presupuesto'])->papel_formato_ancho;
                    $alto = ($input_data['presupuesto'])->papel_formato_alto;
                }

                $papel_generico = (new PapelGenericoModel)->find($linea->papel_id);
                $papel_generico = [
                    'id' => $papel_generico->id,
                    'nombre' => $papel_generico->nombre,
                ];

                // Hay que ver si es rotativa o plana
                // Si es rotativa
                if (str_contains($linea->tipo, '_rot_')) {

                    $datos = [
                        'datosPedido' => (object) array(
                            'paginas' => ($input_data['presupuesto'])->paginas,
                            'tirada' => ($input_data['presupuesto'])->tirada,
                            'merma' => ($input_data['presupuesto'])->merma,
                            'ancho' => $ancho,
                            'alto' => $alto,
                            'a_favor_fibra' => $linea->rotativa_a_favor_fibra,
                            'isCosido' => (new TipoPresupuestoModel())->get_isCosido(($input_data['presupuesto'])->tipo_impresion_id),
                        ),
                        'papel_generico' => $papel_generico,
                        'gramaje' => $linea->gramaje,
                        'paginas' => (object) array(
                            'negro' => ($input_data['presupuesto'])->paginas - $linea->rotativa_pag_color,
                            'color' => $linea->rotativa_pag_color,
                        ),
                        'cliente_id' => ($input_data['presupuesto'])->cliente_id,
                        'datosTipolog' => [
                            (object) array(
                                'negro' => $linea->rotativa_negro,
                                'cyan' => $linea->rotativa_cyan,
                                'magenta' => $linea->rotativa_magenta,
                                'amarillo' => $linea->rotativa_amarillo,
                                'cg' => $linea->rotativa_cg,
                                'gota_negro' => $linea->rotativa_gota_negro,
                                'gota_color' => $linea->rotativa_gota_color,
                            )
                        ]
                    ];

                    $comp_data = PresupuestoService::obtenerComparadorRotativa($datos);
                }
                // Si es plana
                else {

                    $datos = [
                        'tipo_impresion_id' => $data['tipo_impresion_id'],
                        'datosPedido' => (object) array(
                            'paginas' => ($input_data['presupuesto'])->paginas,
                            'tirada' => ($input_data['presupuesto'])->tirada,
                            'merma' => ($input_data['presupuesto'])->merma,
                            'ancho' => $ancho,
                            'alto' => $alto,
                            'a_favor_fibra' => $linea->rotativa_a_favor_fibra,
                            'isCosido' => (new TipoPresupuestoModel())->get_isCosido(($input_data['presupuesto'])->tipo_impresion_id),
                        ),
                        'a_favor_fibra' => $linea->rotativa_a_favor_fibra,
                        'papel_generico' => $papel_generico,
                        'gramaje' => $linea->gramaje,
                        'cliente_id' => ($input_data['presupuesto'])->cliente_id,
                        'datosTipolog' => [
                            (object) array(
                                'negro' => $linea->rotativa_negro,
                                'cyan' => $linea->rotativa_cyan,
                                'magenta' => $linea->rotativa_magenta,
                                'amarillo' => $linea->rotativa_amarillo,
                                'cg' => $linea->rotativa_cg,
                                'gota_negro' => $linea->rotativa_gota_negro,
                                'gota_color' => $linea->rotativa_gota_color,
                            )
                        ]
                    ];

                    // si la línea es cubierta o sobrecubierta, es HQ y color
                    if (str_contains($linea->tipo, 'cubierta')) {
                        $datos['isColor'] = true;
                        $datos['isHq'] = true;

                        // además se añade los campos de lomo y solapas y el uso
                        if (str_contains($linea->tipo, 'sobrecubierta')) {
                            $datos['datosPedido']->solapas = ($input_data['presupuesto'])->solapas_sobrecubierta;
                            $datos['datosPedido']->solapas_ancho = ($input_data['presupuesto'])->solapas_ancho_sobrecubierta;
                            $datos['datosPedido']->lomo = ($input_data['presupuesto'])->lomo_sobrecubierta;
                            $datos['uso'] = 'sobrecubierta';
                        } else {
                            $datos['datosPedido']->solapas = ($input_data['presupuesto'])->solapas;
                            $datos['datosPedido']->solapas_ancho = ($input_data['presupuesto'])->solapas_ancho;
                            $datos['datosPedido']->lomo = ($input_data['presupuesto'])->lomo_cubierta;
                            $datos['uso'] = 'cubierta';
                        }
                    } else {
                        $datos['isColor'] = str_contains($linea->tipo, '_color') ? true : false;
                        $datos['isHq'] = str_contains($linea->tipo, 'hq') ? true : false;
                        $datos['uso'] = 'interior';
                    }

                    if (str_contains($linea->tipo, 'guardas')) {
                        $datos['uso'] = 'guardas';
                        $datos['datosPedido']->paginas_impresion = $linea->paginas_impresion;
                    }

                    $comp_data = PresupuestoService::obtenerComparadorPlana($datos);
                }

                // se ordena $comp_data usando el campo ['fields]['total_impresion']
                usort($comp_data, function ($a, $b) {
                    return $a['fields']['total_impresion'] <=> $b['fields']['total_impresion'];
                });
                (new PresupuestoLineaModel())->updatePreciosLineasPresupuesto($linea->id, $comp_data[0]);
                $linea_to_save = (new PresupuestoLineaModel())->find($linea->id);
                $cambios = true;
                array_push($lineas, $linea_to_save);
            }
            // Si existe el papel y la máquina, se recalcula el precio con los mismos
            // parámetros y se comprueba
            else {
                $nueva_linea = PresupuestoService::obtenerValorLineaPresupuesto($data, $linea);
                if (count($nueva_linea) > 0) {
                    if (round($nueva_linea['fields']['total_impresion'], 2) != round($linea->total_linea, 2)) {
                        (new PresupuestoLineaModel())->updatePreciosLineasPresupuesto($linea->id, $nueva_linea);
                        $linea_to_save = (new PresupuestoLineaModel())->find($linea->id);
                        $cambios = true;
                        array_push($lineas, $linea_to_save);
                    } else {
                        array_push($lineas, $linea);
                    }
                }
            }
        }

        return [$cambios, $lineas];
    }



    private static function obtenerValorLineaPresupuesto($input_data, $linea)
    {

        $tipo_impresion_id = $input_data['tipo_impresion_id'];
        $tirada = $input_data['tirada'];
        $merma = $input_data['merma'];
        $papel_formato_id = $input_data['papel_formato_id'];
        $papel_formato_personalizado = $input_data['papel_formato_personalizado'];
        $ancho = $input_data['papel_formato_ancho'];
        $alto = $input_data['papel_formato_alto'];
        $cliente_id = $input_data['cliente_id'];
        $solapas = $input_data['solapas'];
        $solapas_sobrecubierta = $input_data['solapas_sobrecubierta'];
        $solapas_ancho_cubierta = $input_data['solapas_ancho'];
        $solapas_ancho_sobrecubierta = $input_data['solapas_ancho_sobrecubierta'];
        $lomo_cubierta = $input_data['lomo_cubierta'];
        $lomo_sobrecubierta = $input_data['lomo_sobrecubierta'];

        if ($papel_formato_personalizado == 0) {
            $papel_formato = (new PapelFormatoModel())->find($papel_formato_id);
            $ancho = $papel_formato->ancho;
            $alto = $papel_formato->alto;
        }

        $data = [];
        $output_data = [];

        $papel_impresion = (new PapelImpresionModel())->find($linea->papel_impresion_id);
        $maquina = (new MaquinaModel())->find($linea->maquina_id);
        $maquina->maquina_id = $maquina->id;
        $maquina->maquina = $maquina->nombre;
        $papel_generico = (new PapelGenericoModel())->find($linea->papel_id);
        $papel_generico = array(
            'id' => $papel_generico->id,
            'nombre' => $papel_generico->nombre,
        );

        $data['datosPedido'] = (object) array(
            'paginas' => $linea->paginas,
            'tirada' => $tirada,
            'merma' => $merma,
            'ancho' => $ancho,
            'alto' => $alto,
            'a_favor_fibra' => $linea->rotativa_a_favor_fibra,
            'isCosido' => (new TipoPresupuestoModel())->get_isCosido($tipo_impresion_id),
        );
        $data['cliente_id'] = $cliente_id;
        $data['papel'] = $papel_impresion;
        $data['maquina'] = $maquina;
        $data['papel_generico'] = $papel_generico;
        $data['a_favor_fibra'] = $linea->rotativa_a_favor_fibra;
        $data['datosTipolog'] = [
            (object) array(
                'negro' => $linea->rotativa_negro,
                'cyan' => $linea->rotativa_cyan,
                'magenta' => $linea->rotativa_magenta,
                'amarillo' => $linea->rotativa_amarillo,
                'cg' => $linea->rotativa_cg,
                'gota_negro' => $linea->rotativa_gota_negro,
                'gota_color' => $linea->rotativa_gota_color,
            )
        ];
        $data['gramaje'] = $linea->gramaje;

        switch ($linea->tipo) {

            case 'lp_bn':
            case 'lp_bnhq':
            case 'lp_color':
            case 'lp_colorhq':
            case 'lp_guardas':
                $data['uso'] = 'interior';
                $isColor = strpos($linea->tipo, 'color') !== false;
                $isHq = strpos($linea->tipo, 'hq') !== false;
                $tipo = $isColor ? ($isHq ? 'colorhq' : 'color') : ($isHq ? 'negrohq' : 'negro');
                $opciones_papel = PresupuestoService::get_opciones_papel('interior', $isColor);

                if ($linea->tipo == 'lp_guardas') {
                    $data['uso'] = 'guardas';
                    $tipo = 'colorhq';
                    $data['datosPedido']->paginas_impresion = $linea->paginas_impresion;
                    // Para el caso de Fresado y Cosido tapa dura, las guardas son un diptico
                    // y hay que imprimirlas como "cosido" (dos hojas pegadas). En el caso de espiral
                    // o wire-o tapa dura, las guardas se imprimen como hojas sueltas
                    if ($tipo_impresion_id == 1 || $tipo_impresion_id == 3) {
                        $data['datosPedido']->isCosido = true;
                    } else if ($tipo_impresion_id == 5 || $tipo_impresion_id == 7) {
                        $data['datosPedido']->isCosido = false;
                    }
                }

                $data['tipo'] = $tipo;
                $data['isColor'] = $isColor;
                $data['opciones_papel'] = $opciones_papel;

                $output_data = PresupuestoService::getLineaPresupuestoPlana($data);
                break;


            case 'lp_rot_color':
            case 'lp_rot_bn':
                $data['uso'] = 'interior';
                $tipo = $linea->rotativa_pag_color > 0 ? 'color' : 'negro';
                $data['paginas'] = (object) array(
                    'negro' => $linea->paginas - $linea->rotativa_pag_color,
                    'color' => $linea->rotativa_pag_color,
                );

                $data['tipo'] = $tipo;
                $data['parametrosRotativa'] = (object) array(
                    'a_favor_fibra' => $linea->rotativa_a_favor_fibra,
                    'bnPages' => $data['paginas']->negro,
                    'colorPages' => $data['paginas']->color,
                    'rotativa_negro' => $linea->rotativa_negro,
                    'rotativa_cyan' => $linea->rotativa_cyan,
                    'rotativa_magenta' => $linea->rotativa_magenta,
                    'rotativa_amarillo' => $linea->rotativa_amarillo,
                    'rotativa_gota_negro' => $linea->rotativa_gota_negro,
                    'rotativa_gota_color' => $linea->rotativa_gota_color,
                );

                $output_data = PresupuestoService::getLineaPresupuestoRotativa($data);
                break;

            case 'lp_cubierta':
            case 'lp_sobrecubierta':

                $data['uso'] = ($linea->tipo == 'lp_cubierta') ? 'cubierta' : 'sobrecubierta';
                $data['tipo'] = 'colorhq';
                $data['isColor'] = true;
                $data['datosPedido']->solapas = ($linea->tipo == 'lp cubierta') ? $solapas : $solapas_sobrecubierta;
                $data['datosPedido']->solapas_ancho = ($linea->tipo == 'lp cubierta') ? $solapas_ancho_cubierta : $solapas_ancho_sobrecubierta;
                $data['datosPedido']->lomo = ($linea->tipo == 'lp cubierta') ? $lomo_cubierta : $lomo_sobrecubierta;

                $opciones_papel = PresupuestoService::get_opciones_papel($data['uso'], true);
                $data['opciones_papel'] = $opciones_papel;

                $data['datosPedido']->anchoExteriores = PresupuestoService::getAnchoTotalExteriores($data['uso'], $tipo_impresion_id, $data['datosPedido'], $maquina->maquina_id);
                $data['datosPedido']->altoExteriores = PresupuestoService::getAltoTotalExteriores($data['uso'], $tipo_impresion_id, $data['datosPedido']);

                $output_data = PresupuestoService::getLineaPresupuestoPlana($data);

                if (
                    $tipo_impresion_id == 5 || $tipo_impresion_id == 6 ||
                    $tipo_impresion_id == 7 || $tipo_impresion_id == 8
                ) {

                    $output_data['fields']['num_formas']['num_formas_horizontales'] *= 2;
                    $output_data['fields']['num_formas']['value'] *= 2;
                }
                break;
        }
        return $output_data;
    }

    // Funcion que procesa los servicios y actualiza los precios en caso de cambio
    public static function checkLineasServicios($input_data, $servicios)
    {

        $cambio_en_servicios = false;
        $cambio = false;

        if (count($servicios->serviciosAcabado) > 0) {

            [$cambio, $servicios->serviciosAcabado] =
                PresupuestoService::procesarServiciosAcabado($input_data, $servicios->serviciosAcabado);

            $cambio_en_servicios = $cambio_en_servicios ? $cambio_en_servicios : $cambio;
        }

        if (count($servicios->serviciosManipulado) > 0) {

            [$cambio, $servicios->serviciosManipulado] =
                PresupuestoService::procesarServiciosManipulado($input_data, $servicios->serviciosManipulado);

            $cambio_en_servicios = $cambio_en_servicios ? $cambio_en_servicios : $cambio;
        }

        if (count($servicios->serviciosEncuadernacion) > 0) {

            [$cambio, $servicios->serviciosEncuadernacion] =
                PresupuestoService::procesarServiciosEncuadernacion($input_data, $servicios->serviciosEncuadernacion);

            $cambio_en_servicios = $cambio_en_servicios ? $cambio_en_servicios : $cambio;
        }

        // Los servicios de preimpresion y los extra se dejan tal y como esten

        return [$cambio_en_servicios, $servicios];
    }


    // Funcion que procesa los servicios de acabado del presupuesto
    // y actualiza los precios en caso de cambio de valor en precio_unidad
    private static function procesarServiciosAcabado($input_data, $servicios)
    {

        $serviciosUpdated = [];
        $cambio = false;

        $model = new PresupuestoAcabadosModel();
        foreach ($servicios as $servicio) {

            // Si es un presupuesto duplicado hay que buscar el proveedor más barato
            if ($input_data['is_duplicado']) {
                $nueva_tarifa = $model->getPrecioTarifa($servicio->tarifa_acabado_id, $input_data['tirada'], -1, $input_data['POD']);
            } else {
                $nueva_tarifa = $model->getPrecioTarifa($servicio->tarifa_acabado_id, $input_data['tirada'], $servicio->proveedor_id, $input_data['POD']);
            }

            if ($nueva_tarifa && count($nueva_tarifa) > 0) {
                if (
                    round($nueva_tarifa[0]->precio_unidad, 2) != round($servicio->precio_unidad, 2) ||
                    $nueva_tarifa[0]->margen != $servicio->margen
                ) {

                    $servicio->precio_unidad = round($nueva_tarifa[0]->precio_unidad, 2);
                    $servicio->precio_total = round($nueva_tarifa[0]->total, 2);
                    $servicio->margen = round($nueva_tarifa[0]->margen);
                    $cambio = true;
                }
                array_push($serviciosUpdated, $servicio);
                $servicio_temp = $servicio;
                $servicio_temp->tarifa_id = $servicio_temp->tarifa_acabado_id;
                $model->updateTarifas($input_data['presupuesto_id'], array($servicio_temp));
            }
        }

        return [$cambio, $serviciosUpdated];
    }

    // Funcion que procesa los servicios de manipulado del presupuesto
    // y actualiza los precios en caso de cambio de valor en precio_unidad
    private static function procesarServiciosManipulado($input_data, $servicios)
    {

        $serviciosUpdated = [];
        $cambio = false;

        $model = new PresupuestoManipuladosModel();
        foreach ($servicios as $servicio) {
            $count = 0;
            $nueva_tarifa = $model->getPrecioTarifa($servicio->tarifa_manipulado_id, $input_data['tirada'], $input_data['POD']);
            if ($nueva_tarifa && count($nueva_tarifa) > 0) {
                if (
                    round($nueva_tarifa[0]->precio_unidad, 2) != round($servicio->precio_unidad, 2) ||
                    $nueva_tarifa[0]->margen != $servicio->margen
                ) {

                    $servicio->precio_unidad = round($nueva_tarifa[0]->precio_unidad, 2);
                    $servicio->precio_total = round($nueva_tarifa[0]->total, 2);
                    $servicio->margen = round($nueva_tarifa[0]->margen);
                    $cambio = true;
                }
                array_push($serviciosUpdated, $servicio);
                $servicio_temp = $servicio;
                $servicio_temp->tarifa_id = $servicio_temp->tarifa_manipulado_id;
                $model->updateTarifas($input_data['presupuesto_id'], array($servicio_temp));
            }
        }

        return [$cambio, $serviciosUpdated];
    }


    // Funcion que procesa los servicios de encuadernacion del presupuesto
    // y actualiza los precios en caso de cambio de valor en precio_unidad
    private static function procesarServiciosEncuadernacion($input_data, $servicios)
    {

        $serviciosUpdated = [];
        $cambio = false;

        $model = new PresupuestoEncuadernacionesModel();
        $tarifaModel = model('App\Models\Tarifas\TarifaEncuadernacionModel');

        foreach ($servicios as $servicio) {

            // Si es un presupuesto duplicado hay que buscar el proveedor más barato
            if ($input_data['is_duplicado']) {
                if ($tarifaModel->isTarifaPorHoras($servicio->tarifa_encuadernado_id)) {
                    $paginas_cuadernillo = $servicio->paginas_por_cuadernillo ?? null;
                    $nueva_tarifa = $model->getPrecioTarifaHoras(
                        $servicio->tarifa_encuadernado_id,
                        $input_data['paginas'],
                        $input_data['tirada'],
                        -1,
                        $input_data['POD'],
                        $paginas_cuadernillo
                    );
                } else {
                    $nueva_tarifa = $model->getPrecioTarifa(
                        $servicio->tarifa_encuadernado_id,
                        $input_data['paginas'],
                        $input_data['tirada'],
                        $input_data['ancho'],
                        $input_data['alto'],
                        -1,
                        $input_data['POD']
                    );
                }
            }
            // En caso de que el presupuesto no sea duplicado, recalcular la tarifa 
            // con el mismo proveedor
            else {
                if ($tarifaModel->isTarifaPorHoras($servicio->tarifa_encuadernado_id)) {
                    $paginas_cuadernillo = $servicio->paginas_por_cuadernillo ?? 32;
                    $nueva_tarifa = $model->getPrecioTarifaHoras(
                        $servicio->tarifa_encuadernado_id,
                        $input_data['paginas'],
                        $input_data['tirada'],
                        $servicio->proveedor_id,
                        $input_data['POD'],
                        $paginas_cuadernillo
                    );
                } else {
                    $nueva_tarifa = $model->getPrecioTarifa(
                        $servicio->tarifa_encuadernado_id,
                        $input_data['paginas'],
                        $input_data['tirada'],
                        $input_data['ancho'],
                        $input_data['alto'],
                        $servicio->proveedor_id,
                        $input_data['POD']
                    );
                }
            }


            if ($nueva_tarifa && count($nueva_tarifa) > 0) {
                if (!isset($nueva_tarifa[0]->proveedor_id)) {
                    $nueva_tarifa[0]->proveedor_id = null;
                }
                // Si el presupuesto no es duplicado, se comprueba que
                // no ha cambiado el precio unidad   
                if ($nueva_tarifa[0]->tiempo == null)
                    $nueva_tarifa[0]->tiempo = 0;
                if ($servicio->tiempo == null)
                    $servicio->tiempo = 0;
                if (
                    round($nueva_tarifa[0]->precio_unidad, 2) != round(floatval($servicio->precio_unidad), 2) ||
                    $nueva_tarifa[0]->margen != floatval($servicio->margen) ||
                    $nueva_tarifa[0]->tiempo != floatval($servicio->tiempo)
                ) {

                    $servicio->precio_unidad = round($nueva_tarifa[0]->precio_unidad, 2);
                    $servicio->tiempo = $nueva_tarifa[0]->tiempo == null ? 0 : round($nueva_tarifa[0]->tiempo, 2);
                    $servicio->precio_total = round($nueva_tarifa[0]->total, 2);
                    $servicio->margen = round($nueva_tarifa[0]->margen);
                    $cambio = true;
                } else if ($input_data['is_duplicado'] && $nueva_tarifa[0]->proveedor_id != $servicio->proveedor_id) {
                    $servicio->precio_unidad = round($nueva_tarifa[0]->precio_unidad, 2);
                    $servicio->tiempo = $nueva_tarifa[0]->tiempo == null ? "" : round($nueva_tarifa[0]->tiempo, 2);
                    $servicio->precio_total = round($nueva_tarifa[0]->total, 2);
                    $servicio->margen = round($nueva_tarifa[0]->margen);
                    $servicio->proveedor = $nueva_tarifa[0]->proveedor;
                    $servicio->proveedor_id = $nueva_tarifa[0]->proveedor_id;
                    $cambio = true;
                }
                array_push($serviciosUpdated, $servicio);
                $servicio_temp = $servicio;
                $servicio_temp->tarifa_id = $servicio_temp->tarifa_encuadernado_id;
                $model->updateTarifas($input_data['presupuesto_id'], array($servicio_temp));
            }
        }

        return [$cambio, $serviciosUpdated];
    }


    public static function checkLineasEnvios($envios)
    {

        $cambio = false;

        if (count($envios) > 0) {
            $model = new TarifaEnvioModel();

            foreach ($envios as $envio) {
                $paisId = $envio->pais_id;
                $cp = $envio->cp;
                $peso = $envio->peso;
                $tipo_envio = $envio->entregaPieCalle == 1 ? 'palets' : 'cajas';

                $nueva_tarifa = $model->getTarifaEnvio($paisId, $cp, $peso, $tipo_envio);

                if ($nueva_tarifa && count($nueva_tarifa) > 0) {
                    $coste = 0;
                    $margen = 0;
                    if ($peso > $nueva_tarifa[0]->peso_max) {
                        $coste += floatval($nueva_tarifa[0]->peso_min) + ($peso - floatval($nueva_tarifa[0]->peso_min)) * floatval($nueva_tarifa[0]->precio_adicional);
                    }
                    // si no se calcula linealmente
                    else {
                        $m = (floatval($nueva_tarifa[0]->precio_max) - floatval($nueva_tarifa[0]->precio_min)) / ((floatval($nueva_tarifa[0]->peso_max) - floatval($nueva_tarifa[0]->peso_min)));
                        $b = floatval($nueva_tarifa[0]->precio_max) - $m * floatval($nueva_tarifa[0]->peso_max);
                        $coste += floatval($m * $peso + $b);
                    }
                    $margen += $coste * floatval($nueva_tarifa[0]->margen) / 100.0;

                    if (
                        round($coste, 2) != $envio->precio ||
                        $margen != $envio->margen || $nueva_tarifa[0]->id != $envio->tarifa_id
                    ) {

                        $envio->precio = round($coste, 2);
                        $envio->margen = $margen;
                        $envio->tarifa_id = $nueva_tarifa[0]->id;
                        $cambio = true;

                        $presupuestoDirecciones = new PresupuestoDireccionesModel();
                        $presupuestoDirecciones->updateLineaEnvio($envio);
                    }
                }
            }
        }

        return [$cambio, $envios];
    }


    // Funcion que obtiene el coste para impresión en rotativa
    // y devuelve un array con los datos de la lineas
    // Parametros de entrada: $input_data es un array con los siguientes datos:
    //  - paginas: objeto con las paginas a imprimir en color y negro
    //  - datosPedido: un objeto que contiene los siguientes campos
    //      * paginas: numero total de páginas
    //      * tirada: numero de ejemplares a imprimir
    //      * merma: número de ejemplares extra a imprimir
    //      * ancho: ancho del libro
    //      * alto: alto del libro
    //      * a_favor_fibra: dirección de la impresión 
    //      * isCosido: indica si el libro es cosido o no
    //  - papel_generico: objeto que contiene el id y el nombre del papel generico
    //  - gramaje: gramaje del papel seleccionado
    //  - cliente_id: id del cliente al que va destinado el presupuesto
    //  - datosTipolog: datos referentes a las tintas
    public static function obtenerComparadorRotativa($input_data)
    {

        $paginas = $input_data['paginas'];
        $datosPedido = $input_data['datosPedido'];
        $gramaje = $input_data['gramaje'];
        $papel_generico = $input_data['papel_generico'];
        $cliente_id = $input_data['cliente_id'];
        $datosTipolog = $input_data['datosTipolog'];

        $tipo = $paginas->color > 0 ? 'color' : 'negro';
        $uso = 'interior';

        $parametrosRotativa = (object) array(
            'a_favor_fibra' => $datosPedido->a_favor_fibra,
            'bnPages' => $paginas->negro,
            'colorPages' => $paginas->color,
            'rotativa_gota_negro' => 0,
            'rotativa_gota_color' => 0,
        );

        $opciones_papel = array(
            'rotativa' => 1,
        );

        $tipo = array();
        if ($paginas->color > 0) {
            $tipo = 'color';
            $opciones_papel['color'] = 1;
        } else {
            $opciones_papel['bn'] = 1;
            $tipo = 'negro';
        }

        // Se obtienen los papeles disponibles
        $papelimpresionmodel = new PapelImpresionModel();
        $papeles = $papelimpresionmodel->getIdPapelesImpresionForPresupuesto(
            papel_generico_id: $papel_generico['id'],
            gramaje: $gramaje,
            options: $opciones_papel
        );

        $lineas = array();
        // Para cada papel, se obtienen las maquinas disponibles
        foreach ($papeles as $papel) {

            $papelImpresionTipologiaModel = new \App\Models\Configuracion\PapelImpresionTipologiaModel();
            if (is_null($datosTipolog)) {
                $datosTipologias = $papelImpresionTipologiaModel
                    ->findTipologiasForPapelImpresion($papel->id, $parametrosRotativa->colorPages > 0 ? 'color' : 'negro')
                    ->get()->getResultObject();


                if (count($datosTipologias) == 0) {
                    continue;
                }
            } else {
                $datosTipologias = $datosTipolog;
            }

            $parametrosRotativa->rotativa_gota_negro = $datosTipologias[0]->gota_negro;
            $parametrosRotativa->rotativa_gota_color = $datosTipologias[0]->gota_color;
            $parametrosRotativa->rotativa_negro = $datosTipologias[0]->negro;
            $parametrosRotativa->rotativa_cyan = $datosTipologias[0]->cyan;
            $parametrosRotativa->rotativa_magenta = $datosTipologias[0]->magenta;
            $parametrosRotativa->rotativa_amarillo = $datosTipologias[0]->amarillo;

            $maquinamodel = new MaquinaModel();

            $maquinas = $maquinamodel->getMaquinaImpresionForPresupuesto(
                is_rotativa: 1,
                tarifa_tipo: $tipo,
                uso_tarifa: $uso,
                tirada: $datosPedido->tirada + $datosPedido->merma,
                papel_impresion_id: $papel->id,
            )->orderBy("t1.id", "asc")->get()->getResultObject();

            $data['uso'] = $uso;
            $data['tipo'] = $tipo;
            $data['datosPedido'] = $datosPedido;
            $data['cliente_id'] = $cliente_id;
            $data['papel'] = $papel;
            $data['papel_generico'] = $papel_generico;
            $data['parametrosRotativa'] = $parametrosRotativa;
            $data['paginas'] = $paginas;
            $data['gramaje'] = $gramaje;

            // Se recorren las máquinas y se calcula el coste de linea por cada una
            foreach ($maquinas as $maquina) {

                $data['maquina'] = $maquina;

                $linea = PresupuestoService::getLineaPresupuestoRotativa($data);

                if (empty($linea))
                    continue;

                array_push($lineas, $linea);
            }
        }
        return $lineas;
    }


    // Funcion que obtiene el coste para impresión en plana
    // y devuelve un array con los datos de la lineas
    // Parametros de entrada: $input_data es un array con los siguientes datos:
    //  - uso: 'interior', 'guardas', 'cubierta' o 'sobrecubierta'
    //  - tipo_impresion_id: id del tipo de impresion
    //  - datosPedido: un objeto que contiene los siguientes campos
    //      * paginas: numero total de páginas
    //      * tirada: numero de ejemplares a imprimir
    //      * merma: número de ejemplares extra a imprimir
    //      * ancho: ancho del libro
    //      * alto: alto del libro
    //      * a_favor_fibra: dirección de la impresión 
    //      * isCosido: indica si el libro es cosido o no
    //      * solapas: (solo cubierta y sobrecubierta) indica si hay o no solapas
    //      * solapas_ancho: (solo cubierta y sobrecubierta) indica el ancho de las solapas
    //      * lomo: (solo cubierta y sobrecubierta) ancho del lomo del libro (o libro mas cubierta)
    //  - papel_generico: objeto que contiene el id y el nombre del papel generico
    //  - gramaje: gramaje del papel seleccionado
    //  - cliente_id: id del cliente al que va destinado el presupuesto
    //  - datosTipolog: datos referentes a las tintas (opcional)
    //  - a_favor_fibra: dirección de la impresión 
    public static function obtenerComparadorPlana($input_data)
    {

        $uso = $input_data['uso'];
        $tipo_impresion_id = $input_data['tipo_impresion_id'];
        $datosPedido = $input_data['datosPedido'];
        $papel_generico = $input_data['papel_generico'];
        $gramaje = $input_data['gramaje'];
        $isColor = $input_data['isColor'];
        $isHq = $input_data['isHq'];
        $cliente_id = $input_data['cliente_id'];
        $datosTipolog = $input_data['datosTipolog'] ?? null;
        $a_favor_fibra = $datosPedido->a_favor_fibra ?? false;
        $lomoRedondo = $input_data['lomoRedondo'] ?? 0;

        $tipo = $isColor ? ($isHq ? 'colorhq' : 'color') : ($isHq ? 'negrohq' : 'negro');

        $uso_papel = $uso == 'faja' ? 'sobrecubierta' : $uso;
        $opciones_papel = PresupuestoService::get_opciones_papel($uso_papel, $isColor);

        // Se obtienen los papeles disponibles
        $papelimpresionmodel = new PapelImpresionModel();
        $papeles = $papelimpresionmodel->getIdPapelesImpresionForPresupuesto(
            papel_generico_id: $papel_generico['id'],
            gramaje: $gramaje,
            options: $opciones_papel
        );

        $lineas = array();
        // Para cada papel, se obtienen las maquinas disponibles
        foreach ($papeles as $papel) {

            $maquinamodel = new MaquinaModel();
            $maquinas = $maquinamodel->getMaquinaImpresionForPresupuesto(
                is_rotativa: 0,
                tarifa_tipo: $tipo,
                uso_tarifa: ($uso == 'guardas') ? 'interior' : $uso_papel,
                tirada: $datosPedido->tirada + $datosPedido->merma,
                papel_impresion_id: $papel->id,
            )->orderBy("t1.id", "asc")->get()->getResultObject();

            // Se recorren las máquinas y se calcula el coste de linea por cada una
            foreach ($maquinas as $maquina) {

                if ($uso == 'cubierta' || $uso == 'sobrecubierta' || $uso == 'faja') {

                    $datosPedido->anchoExteriores = PresupuestoService::getAnchoTotalExteriores($uso, $tipo_impresion_id, $datosPedido, $maquina->maquina_id, $lomoRedondo);
                    $datosPedido->altoExteriores = PresupuestoService::getAltoTotalExteriores($uso, $tipo_impresion_id, $datosPedido);
                }

                $data['uso'] = $uso;
                $data['tipo'] = $tipo;
                $data['datosPedido'] = $datosPedido;
                $data['cliente_id'] = $cliente_id;
                $data['papel'] = $papel;
                $data['opciones_papel'] = $opciones_papel;
                $data['maquina'] = $maquina;
                $data['papel_generico'] = $papel_generico;
                $data['isColor'] = $isColor;
                $data['a_favor_fibra'] = $a_favor_fibra;
                $data['datosTipolog'] = $datosTipolog;
                $data['gramaje'] = $gramaje;

                $linea = PresupuestoService::getLineaPresupuestoPlana($data);

                if (empty($linea))
                    continue;

                if (
                    $tipo_impresion_id == 5 || $tipo_impresion_id == 6 ||
                    $tipo_impresion_id == 7 || $tipo_impresion_id == 8
                ) {

                    if ($uso == 'cubierta') {
                        $linea['fields']['num_formas']['num_formas_horizontales'] *= 2;
                        $linea['fields']['num_formas']['value'] *= 2;
                    }
                }

                if ($uso == 'cubierta' || $uso == 'sobrecubierta' || $uso == 'faja') {

                    $linea['fields']['dimension_desarrollo']['ancho'] = $datosPedido->anchoExteriores;
                    $linea['fields']['dimension_desarrollo']['alto'] = $datosPedido->altoExteriores;
                }

                if (!array_key_exists('tipo_linea', $linea['fields'])) {
                    if ($isColor) {
                        if ($isHq)
                            $linea['fields']['tipo_linea'] = 'lp_colorhq';
                        else
                            $linea['fields']['tipo_linea'] = 'lp_color';
                    } else {
                        if ($isHq)
                            $linea['fields']['tipo_linea'] = 'lp_bnhq';
                        else
                            $linea['fields']['tipo_linea'] = 'lp_bn';
                    }
                }
                array_push($lineas, $linea);
            }
        }
        return $lineas;
    }



    public static function crearPedido($presupuesto_id)
    {
        $model_pedido = model('App\Models\Pedidos\PedidoModel');
        $model_pedido_linea = model('App\Models\Pedidos\PedidoLineaModel');
        $model_cliente = model('App\Models\Clientes\ClienteModel');

        $model_presupuesto = model('App\Models\Presupuestos\PresupuestoModel');
        $datos_presupuesto = $model_presupuesto->find($presupuesto_id);

        $id_linea = 0;

        $data_pedido = [
            'total_precio' => $datos_presupuesto->total_aceptado,
            'total_tirada' => $datos_presupuesto->tirada,
            'estado' => $model_cliente->creditoDisponible($datos_presupuesto->cliente_id, $datos_presupuesto->total_aceptado) ? "produccion" : "validacion",
            'user_created_id' => auth()->user()->id,
            'user_updated_id' => auth()->user()->id,
        ];

        $pedido_id = $model_pedido->insert($data_pedido);
        if ($pedido_id) {
            $lineas_pedido = $model_presupuesto->generarLineaPedido($presupuesto_id)[0];
            $data_pedido_linea = [
                "pedido_id" => $pedido_id,
                "presupuesto_id" => $presupuesto_id,
                'cantidad' => $lineas_pedido->unidades,
                'descripcion' => $lineas_pedido->concepto,
                "ubicacion_id" => 1, // safetak por defecto
                "user_created_id" => auth()->user()->id,
                "user_updated_id" => auth()->user()->id,
            ];
            $id_linea = $model_pedido_linea->insert($data_pedido_linea);
            PedidoXMLService::generate_xml($pedido_id);
        }

        if ($id_linea != 0 && $pedido_id != 0) {
            if ($data_pedido['estado'] == "produccion") {

                $serviceProduction = service('production');
                $modelPedido = model('App\Models\Pedidos\PedidoModel');
                $pedido = $modelPedido->find($pedido_id);
                $serviceProduction->setPedido($pedido);
                if (!$pedido->orden_trabajo()) {
                    
                    $r = $serviceProduction->createOrdenTrabajo();
                    $modelPedido->set(['estado' => 'produccion'])->where('id', $pedido_id)->update();
                }
            }
            return true;
        }
        return false;
    }

    /********************************+
     * FUNCIONES AUXILIARES          *
     *******************************/

    // Funcion que comprueba si existe una maquina
    private static function checkMaquina($maquina_id)
    {

        $maquina = (new MaquinaModel())->find($maquina_id);
        if (!$maquina) {
            return false;
        }
        return true;
    }


    // Funcion que comprueba si existe un papel de impresion
    private static function checkPapelImpresion($papel_impresion_id)
    {

        $papel = (new PapelImpresionModel())->find($papel_impresion_id);
        if (!$papel) {
            return false;
        }
        return true;
    }


    /**
     * Devuelve la dimensión del lomo interior.
     */
    private static function computeLomoInterior($paginas = null, $espesor = null)
    {
        $lomo = 0;

        if (!is_null($paginas) && !is_null($espesor)) {

            $lomo += (($espesor * $paginas / 2.0) + 1) / 1000.0;
        }

        return $lomo;
    }

    /**
     * Calcula la dimensión del lomo para portada y cubierta
     */
    private static function computeLomoPortada($espesor)
    {
        return ($espesor * 2.0) / 1000.0;
    }

    /**
     * Devuelve el peso de un pedido.
     */
    private static function computePeso($ancho, $alto, $gramaje, $paginas = null)
    {
        $peso = ($ancho / 1000.0) * ($alto / 1000.0) * $gramaje;

        if (!is_null($paginas)) {
            if ($paginas > 0) {
                $peso *= ($paginas / 2.0);
            }
        }

        return $peso;
    }
}
