<?php

declare(strict_types=1);

namespace App;

use RuntimeException;
use SimpleXMLElement;

final class MdfeXmlParser
{
    private const MDFE_NAMESPACE = 'http://www.portalfiscal.inf.br/mdfe';

    /**
     * @return array{
     *   cpf_motorista: string,
     *   nome_motorista: string,
     *   placa_veiculo: string,
     *   rntrc: string,
     *   valor_frete: float,
     *   origem: array{cidade: string, uf: string},
     *   destino: array{cidade: string, uf: string},
     *   mdfe: array<string, mixed>,
     *   cte: array<string, mixed>,
     *   referencia_externa: string
     * }
     */
    public function parseToCiotPayload(string $xmlFilePath): array
    {
        if (!is_file($xmlFilePath) || !is_readable($xmlFilePath)) {
            throw new RuntimeException('Arquivo XML MDF-e nao encontrado ou sem permissao de leitura: ' . $xmlFilePath);
        }

        $xml = simplexml_load_file($xmlFilePath);
        if (!$xml instanceof SimpleXMLElement) {
            throw new RuntimeException('Nao foi possivel carregar o XML MDF-e.');
        }

        $xml->registerXPathNamespace('m', self::MDFE_NAMESPACE);

        $mdfeId = $this->getAttribute($xml, '//m:infMDFe', 'Id');
        $mdfeKey = preg_replace('/\D+/', '', $mdfeId) ?? '';
        $cteKey = $this->getValue($xml, '//m:infCTe/m:chCTe', false);

        return [
            'cpf_motorista' => $this->getValue($xml, '//m:condutor/m:CPF'),
            'nome_motorista' => $this->getValue($xml, '//m:condutor/m:xNome'),
            'placa_veiculo' => $this->getValue($xml, '//m:veicTracao/m:placa'),
            'rntrc' => $this->getValue($xml, '//m:infANTT/m:RNTRC'),
            'valor_frete' => (float)$this->getValue($xml, '//m:infPag/m:vContrato'),
            'origem' => [
                'cidade' => $this->getValue($xml, '//m:infMunCarrega/m:xMunCarrega'),
                'uf' => $this->getValue($xml, '//m:ide/m:UFIni'),
            ],
            'destino' => [
                'cidade' => $this->getValue($xml, '//m:infMunDescarga/m:xMunDescarga'),
                'uf' => $this->getValue($xml, '//m:ide/m:UFFim'),
            ],
            'mdfe' => [
                'chave' => $mdfeKey,
                'id' => $mdfeId,
                'numero' => $this->getValue($xml, '//m:ide/m:nMDF', false),
                'serie' => $this->getValue($xml, '//m:ide/m:serie', false),
                'data_emissao' => $this->getValue($xml, '//m:ide/m:dhEmi', false),
                'emitente_cnpj' => $this->getValue($xml, '//m:emit/m:CNPJ', false),
                'emitente_nome' => $this->getValue($xml, '//m:emit/m:xNome', false),
            ],
            'cte' => [
                'chave' => $cteKey,
            ],
            'referencia_externa' => $mdfeKey !== '' ? 'MDFE-' . $mdfeKey : basename($xmlFilePath),
        ];
    }

    private function getValue(SimpleXMLElement $xml, string $xpath, bool $required = true): string
    {
        $nodes = $xml->xpath($xpath);
        $value = isset($nodes[0]) ? trim((string)$nodes[0]) : '';

        if ($required && $value === '') {
            throw new RuntimeException('Campo obrigatorio nao encontrado no XML MDF-e: ' . $xpath);
        }

        return $value;
    }

    private function getAttribute(SimpleXMLElement $xml, string $xpath, string $attributeName): string
    {
        $nodes = $xml->xpath($xpath);
        if (!isset($nodes[0])) {
            throw new RuntimeException('No obrigatorio nao encontrado no XML MDF-e: ' . $xpath);
        }

        $attributes = $nodes[0]->attributes();
        $value = isset($attributes[$attributeName]) ? trim((string)$attributes[$attributeName]) : '';

        if ($value === '') {
            throw new RuntimeException('Atributo obrigatorio nao encontrado no XML MDF-e: ' . $attributeName);
        }

        return $value;
    }
}
