<?php

namespace Oneweb\SimuladorSitef;

class Arquivo
{
    /**
     * @var \Oneweb\SimuladorSitef\SitefRegistro[]
     */
    private array $registros = [];

    public function __construct(string $conteudo)
    {
        $this->setConteudo($conteudo);
    }

    private function setConteudo(string $conteudo): void
    {
        $linhas = array_filter(explode("\r\n", $conteudo));
        if (count($linhas) === 1) {
            if (str_contains($conteudo, "\n")) {
                $linhas = array_filter(explode("\n", $conteudo));
            }
        }

        $this->registros = [];
        foreach ($linhas as $linha) {
            if (str_starts_with($linha, '#')) {
                continue;
            }
            $registro = SitefRegistro::createFromString($linha);
            if (!$registro) {
                $ultimoIndice = count($this->registros) - 1;
                $this->registros[$ultimoIndice]->adicionarConteudo($linha);

                continue;
            }

            $this->registros[] = $registro;
        }
    }

    public function __toString(): string
    {
        return rtrim(implode('', $this->registros));
    }

    public function adicionarRegistro(string $identificacao, string $conteudo, ?int $nSequencia = null): void
    {
        if ($nSequencia === null) {
            $nSequencia = $this->getProximoNSequencia($identificacao);
        }
        $this->registros[] = SitefRegistro::create($identificacao, $conteudo, $nSequencia);
    }

    private function getProximoNSequencia(string $identificacao): int
    {
        return count($this->getRegistros($identificacao));
    }

    /**
     * @return \Oneweb\SimuladorSitef\SitefRegistro[]
     */
    public function getRegistros(int|string $identificacao, ?int $nSequencia = null): array
    {
        if (str_contains($identificacao, '-')) {
            [$identificacao, $nSequencia] = explode('-', $identificacao);
        }

        return array_values(array_filter($this->registros, function ($valor) use ($identificacao, $nSequencia) {
            $isIgual = (int)$valor->getIdentificacao() == (int)$identificacao;
            if (isset($nSequencia) && $nSequencia != '') {
                $isIgual = $isIgual && $valor->getNSequencia() == $nSequencia;
            }

            return $isIgual;
        }));
    }

    public function getConteudo(int|string $identificacao, ?int $nSequencia = null): array
    {
        $registros = $this->getRegistros($identificacao, $nSequencia);

        return array_map(function ($registro) {
            return $registro->getConteudo();
        }, $registros);
    }

    public function getConteudoRegistro(int|string $identificacao, int|string $nSequencia = 0): ?string
    {
        return $this->getConteudo($identificacao, (int)$nSequencia)[0] ?? null;
    }

    public function isRequisicaoPix(): bool
    {
        return $this->getConteudoRegistro('000') == 'PIX';
    }

    public function isRequisicaoColetaDados(): bool
    {
        return $this->getConteudoRegistro('000') == 'CLT';
    }

    public function isRequisicaoCartao(): bool
    {
        return $this->getConteudoRegistro('000', 0) == 'CRT';
    }

    public function isConfirmacaoImpressao(): bool
    {
        return $this->getConteudoRegistro('000', 0) == 'CNF';
    }

    public function setValorRegistro(string|int $identificacao, int|string $sequencia, string $valor): void
    {
        foreach ($this->registros as $i => $registro) {
            if ((int)$registro->getIdentificacao() == (int)$identificacao && $registro->getNSequencia() == $sequencia) {
                $this->registros[$i]->setConteudo($valor);
            }
        }
    }

    public function deveGerarArquivoRetorno(): bool
    {
        return $this->isRequisicaoCartao() || $this->isRequisicaoPix() || $this->isRequisicaoColetaDados();
    }
}
