<?php

class Seguro_Service_Cotacao
{
    /**
     * @param int $idCotacao
     * @return Zend_Db_Table_Row_Abstract|null
     * @throws Zend_Controller_Action_Exception
     * @throws Zend_Db_Table_Exception
     */
    public function getById(int $idCotacao): ?Zend_Db_Table_Row_Abstract
    {
        if (empty($idCotacao)) {
            throw new Zend_Controller_Action_Exception('ID da cotação não informado.', 400);
        }

        return (new Seguro_Model_Cotacoes())->find($idCotacao)->current();
    }

    public function getUnidades(int $idCotacao): array
    {
        return (new Seguro_Model_CotacoesUnidades())->getUnidades(
            [
                'scu.vl_area as area',
                'scu.vl_produtividade as produtividade',
                'scu.vl_tonelada as tonelada',
                'scu.id',
            ],
            ["id_cotacao = {$idCotacao}"]
        )->toArray();
    }

    public function organizarTaxasCoberturas(array $taxasCoberturas, bool $todasPossibilidades = true): array
    {
        if ($todasPossibilidades) {
            return $this->organizarTaxasCoberturasCompleta($taxasCoberturas);
        }

        return $this->organizarTaxasCoberturasUnica($taxasCoberturas);
    }

    private function organizarTaxasCoberturasCompleta(array $taxasCoberturas): array
    {
        $taxas = $taxasOrganizadasCalculo = [];

        foreach ($taxasCoberturas as $taxa) {
            $tipo = $taxa['fl_cobertura_principal'] ? 'cobertura_principal' : 'cobertura_adicional';
            $taxas[$tipo][$taxa['id_cobertura']][] = $taxa;
        }

        foreach ($taxas['cobertura_principal'] as $coberturaPrincipalFranquias) {
            foreach ($coberturaPrincipalFranquias as $coberturaPrincipalFranquia) {
                $taxasOrganizadasCalculo[] = ['cobertura_principal' => $coberturaPrincipalFranquia];

                // 2) Cobertura principal + combinações adicionais
                $coberturasAdicionais = array_keys($taxas['cobertura_adicional']);
                $totalCoberturasAdicionais = count($coberturasAdicionais);

                // Gerar combinações de adicionais (1 até N)
                for ($contador = 1; $contador <= $totalCoberturasAdicionais; $contador++) {
                    $combinacoes = $this->gerarCombinacoes($coberturasAdicionais, $contador);
                    foreach ($combinacoes as $combo) {
                        $item = ['cobertura_principal' => $coberturaPrincipalFranquia];
                        foreach ($combo as $adicionalKey) {
                            $item['coberturas_adicionais'][$adicionalKey] = $taxas['cobertura_adicional'][$adicionalKey][0];
                        }

                        $taxasOrganizadasCalculo[] = $item;
                    }
                }
            }
        }

        return $taxasOrganizadasCalculo;
    }

    private function gerarCombinacoes(array $coberturasAdicionais, $contadorAdicional): array
    {
        $results = [];
        $numeroCoberturasAdicionais = count($coberturasAdicionais);
        $indices = range(0, $contadorAdicional - 1);
        while (true) {
            $combo = [];
            foreach ($indices as $i) {
                $combo[] = $coberturasAdicionais[$i];
            }

            $results[] = $combo;
            $contador = $contadorAdicional - 1;
            while (
                $contador >= 0
                && $indices[$contador] == ($numeroCoberturasAdicionais - $contadorAdicional + $contador)
            ) {
                $contador--;
            }

            if ($contador < 0) {
                break;
            }

            $indices[$contador]++;
            for ($novoContador = $contador + 1; $novoContador < $contadorAdicional; $novoContador++) {
                $indices[$novoContador] = $indices[$novoContador - 1] + 1;
            }
        }

        return $results;
    }

    private function organizarTaxasCoberturasUnica(array $taxasCoberturas): array
    {
        $taxaCoberturaPrincipal = $taxaCoberturasAdicionais = [];
        foreach ($taxasCoberturas as $taxa) {
            if ($taxa['fl_cobertura_principal']) {
                $taxaCoberturaPrincipal['cobertura_principal'] = $taxa;
            } else {
                $taxaCoberturasAdicionais['coberturas_adicionais'][] = $taxa;
            }
        }

        return [array_merge($taxaCoberturasAdicionais, $taxaCoberturaPrincipal)];
    }

    /**
     * @param array $unidadesSeguradas
     * @param bool $produtividadeGarantida
     * @param float|null $valorProdutividadeEstimada
     * @param float|null $franquia
     * @return array
     * @throws Zend_Exception
     */
    public function calcularLmga(
        array $unidadesSeguradas,
        bool  $produtividadeGarantida,
        float $valorProdutividadeEstimada = null,
        float $franquia = null
    ): array
    {
        $lmga = $valorProdutividadeBase = 0;
        foreach ($unidadesSeguradas as $unidade) {
            if (
                empty($unidade['area_segurada'])
                || empty($unidade['valor_tonelada'])
                || !isset($unidade['produtividade'])
            ) {
                throw new Zend_Exception(
                    'Área, Valor Tonelada e Produtividade são campos obrigatórios para cada unidade.',
                    400
                );
            }

            $areaSegurada = number_format(Agro_Util::formatCurrencyDb($unidade['area_segurada']), 2, '.', '');
            $valorTonelada = number_format(Agro_Util::formatCurrencyDb($unidade['valor_tonelada']), 2, '.', '');
            $valorProdutividadeBase = $produtividadeGarantida
                ? $valorProdutividadeEstimada
                : $unidade['produtividade'];
            $produtividade = number_format(Agro_Util::formatCurrencyDb($valorProdutividadeBase), 3, '.', '');
            $produtividade = $produtividadeGarantida
                ? round($franquia * ($produtividade / 100), 3)
                : $produtividade;
            $lmga += $areaSegurada * $produtividade * $valorTonelada;
        }

        return [
            'lmga' => $lmga,
            'valorProdutividadeBase' => $valorProdutividadeBase,
        ];
    }
}