<?php

declare(strict_types=1);

class Sinistro2_Service_Gerarcobranca
{
	public function gerarCobranca(array $idsVistorias, bool $isPrevia): int
	{
		$modelVistoriadorDespesa = new Sinistro2_Model_VistoriadorDespesa();
		$modelVistoria = new Sistema_Model_Vistorias();
		$modelLaudo = $isPrevia
			? (new Sinistro2_Model_CobrancaPreviaEssor())
			: (new Sinistro2_Model_CobrancaPreliminarFinalEssor());

		// Buscar ids propostas e funcionarios das vistorias selecionadas
		$dadosVistorias = $modelVistoria->getDadosPorIdsVistorias($idsVistorias, $isPrevia);
		$mapIdPropostaDadosVistoria = $mapIdFuncionario = $idsPropostas = [];
		$map = $mapIdPropostaIdPropostaMae = [];
		
		foreach ($dadosVistorias as $vistoria) {
			$idsFuncionarios = explode(',', $vistoria['ids_funcionarios']);
			$mapIdPropostaDadosVistoria[$vistoria['id_proposta']] = $vistoria;
			$idsPropostas[] = $vistoria['id_proposta'];
			$data = substr($vistoria['dt_vistoria'], 0, 10);
			$mapIdPropostaIdPropostaMae[$vistoria['id_proposta']] = $vistoria['id_proposta_mae'];

			// Mapeia vistoria por proposta, funcionario e data
			foreach ($idsFuncionarios as $idFuncionario) {
				$mapIdFuncionario[$idFuncionario] = $idFuncionario;
				$map[$vistoria['id_proposta']][$idFuncionario][$data] = $vistoria;
			}
		}

		// Buscar despesas sem vínculo vistoria com base nos ids propostas e funcionários
		$despesasSemVinculo = $modelVistoriadorDespesa->getDespesasPorPropostaFuncionarioSemVinculoVistoria(
			$idsPropostas,
			$mapIdFuncionario
		);
		
		$mapIdVistoriaIdsDespesas = [];
		$mapIdVistoriaDespesas = [];
		$idsDespesasSemVistoriasParaVincular = [];
		$mapPropostasDepesaKm = [];

		// Verifica se há vistoria cuja data bate com data da despesa
		foreach ($despesasSemVinculo as $despesa) {
			$data = substr($despesa['dt_despesa'], 0, 10);

			if ($despesa['id_tipo_despesa'] == Sinistro2_Model_TipoDespesa::TIPO_DESPESA_KM) {
				$mapPropostasDepesaKm[$despesa['id_proposta']] = true;
			}

			$vistoria = $map[$despesa['id_proposta']][$despesa['id_funcionario']][$data];
			if (empty($vistoria) || $vistoria['id_estado'] != $despesa['id_estado']) {
				$idsDespesasSemVistoriasParaVincular[$despesa['id']] = $despesa['id'];
				continue;
			}
			
			$mapIdVistoriaIdsDespesas[$vistoria['id_vistoria']][] = $despesa['id'];
			$mapIdVistoriaDespesas[$vistoria['id_vistoria']][] = $despesa;
		}
		
		$idsPropostasSemQuilometragem = '';

		// Valida se todas propostas possuem despesas de quilometragem
		foreach ($idsPropostas as $id) {
			if (!array_key_exists($id, $mapPropostasDepesaKm)) {
				$idPropostaMae = $mapIdPropostaIdPropostaMae[$id];
				$idsPropostasSemQuilometragem .= !empty($idsPropostasSemQuilometragem)
					? ", {$idPropostaMae}"
					: $idPropostaMae;
			}
		}

		if (!empty($idsPropostasSemQuilometragem)) {
			$mensagem = "Não foi possível gerar o relatório de cobrança.\n\n";
			$mensagem .= "As seguintes propostas não possuem despesas de quilometragem vinculadas: {$idsPropostasSemQuilometragem}";
			
			throw new Exception($mensagem);
		}
	
		// Vincula vistorias
		$modelVistoriadorDespesa->vinculaVistorias($mapIdVistoriaIdsDespesas);
		$dados = $this->getTotalDespesaTotalKmPorVistoria($mapIdVistoriaDespesas, $isPrevia);
		
		unset($mapIdVistoriaDespesas);
		unset($mapIdVistoriaIdsDespesas);
		unset($despesasSemVinculoVistoria);
		
		$rsVistoria = $modelVistoria->getIdsPropostasDatasVistorias($idsVistorias , $isPrevia);
		$vistorias = [];
		
		// Monta array com id, id_proposta e dt_vistoria para utilizar no service Buscahonorarios
		foreach ($rsVistoria as $vistoria) {
			$vistorias[] = [
				'id' => $vistoria['id_vistoria'],
				'id_proposta' => $vistoria['id_proposta'],
				'dt_vistoria' => $vistoria['dt_vistoria'],
			];
		}
		
		$honorarios = (new Sinistro2_Service_Buscahonorarios($isPrevia))->buscaHonorarios($vistorias);
		$totalHonorarios = $honorarios['notaHonorarios'];
		
		foreach ($honorarios['dados'] as $vistoria) {
			if (!empty($dados['vistorias'][$vistoria['id_vistoria']])) {
				$dados['vistorias'][$vistoria['id_vistoria']]['honorarios'] = $vistoria['vistoriaHonorarios'];
			} else {
				$dados['vistorias'][$vistoria['id_vistoria']] = [
					'id_vistoria' => $vistoria['id_vistoria'],
					'despesas' => 0,
					'km_quantidade' => 0,
					'km_valor' => 0,
					'alimentacao' => 0,
					'pedagio' => 0,
					'hotel' => 0,
					'honorarios' => $vistoria['vistoriaHonorarios']
				];
			}
		}

		$dados['nota_honorarios'] = $totalHonorarios;
		$dados['nota_valor_km'] = $dados['totalDespesaGasolina'];
		$dados['nota_despesas'] = $dados['totalDespesas'];
		$dados['tipo_relatorio'] = $isPrevia ? 'P' : 'F';
		$dados['id_status'] = (new Sistema_Model_Status())->getId('NAO_ENVIADO','RELATORIO_COBRANCA');
		
		$idCobrancaRelatorio = $modelLaudo->save($dados);
		if (!$idCobrancaRelatorio) {
			throw new Exception('Erro ao gerar relatório!');
		}
		
		return $idCobrancaRelatorio;
	}

    // Calcula total de despesas para vistorias com despesas vinculadas
	private function getTotalDespesaTotalKmPorVistoria(array $despesasVistorias, bool $isPrevia): array
	{
		$modelCombustivel = new Sinistro2_Model_CobrancaValorCombustivel();
		
		$totalDespesas = $totalDespesasGasolina = 0;
		$mapKmVistoria = $idsVistoriasComKm = [];

		$vistoriasTotais = [];
		
		foreach ($despesasVistorias as $idVistoria => $despesas) {
			$totalKmRodadosVistoria = 0;
			$totalDespesasVistoria = 0;
			$totalDespesasHotelVistoria = 0;
			$totalDespesasPedagioVistoria = 0;
			$totalDespesasAlimentacaoVistoria = 0;

			foreach ($despesas as $despesa) {
				switch($despesa['id_tipo_despesa']) {
					case Sinistro2_Model_TipoDespesa::TIPO_DESPESA_KM:
						$totalKmRodadosVistoria += $despesa['vl_despesa'];
						break;
					case Sinistro2_Model_TipoDespesa::TIPO_DESPESA_PEDAGIO:
						$totalDespesasPedagioVistoria += $despesa['vl_despesa'];
						break;
					case Sinistro2_Model_TipoDespesa::TIPO_DESPESA_HOTEL:
						$totalDespesasHotelVistoria += $despesa['vl_despesa'];
						break;
					case Sinistro2_Model_TipoDespesa::TIPO_DESPESA_ALIMENTACAO:
						$totalDespesasAlimentacaoVistoria += $despesa['vl_despesa'];
						break;
					default:
						break;
				}

				if ($despesa['id_tipo_despesa'] != Sinistro2_Model_TipoDespesa::TIPO_DESPESA_KM) {
					$totalDespesasVistoria += $despesa['vl_despesa'];
				}
			}

			$totalDespesas += $totalDespesasVistoria;

			if ($totalKmRodadosVistoria) {
				$mapKmVistoria[$idVistoria] = $totalKmRodadosVistoria;
				$idsVistoriasComKm[] = $idVistoria;
			}

			$vistoriasTotais[$idVistoria] = [
				'id_vistoria' => $idVistoria,
				'despesas' => $totalDespesasVistoria,
				'km_quantidade' => $totalKmRodadosVistoria,
				'alimentacao' => $totalDespesasAlimentacaoVistoria,
				'pedagio' => $totalDespesasPedagioVistoria,
				'hotel' => $totalDespesasHotelVistoria,
				'km_valor' => 0,
				'honorarios' => 0
			];
		}
		
		if (!empty($idsVistoriasComKm)) {
			$mapIdVistoriaValorCombustivel = $modelCombustivel->getValorCombustivelPorVistorias($idsVistoriasComKm, $isPrevia);
			
			if (empty($mapIdVistoriaValorCombustivel)) {
				throw new Exception('Preço do combustível não encontrado para calcular despesas de deslocamento.');
			}

			foreach ($mapKmVistoria as $idVistoria => $km) {
				$custoKm = Sinistro2_Model_CobrancaValorCombustivel::calculaGastoCombustivel(
					$km,
					$mapIdVistoriaValorCombustivel[$idVistoria]
				);

				$custoKm = round($custoKm, 2);

				$totalDespesasGasolina += $custoKm;
				$vistoriasTotais[$idVistoria]['km_valor'] += $custoKm;
			}
		}

		return [
			'vistorias' => $vistoriasTotais,
			'totalDespesaGasolina' => $totalDespesasGasolina,
			'totalDespesas' => $totalDespesas
		];
	}
}