<?php

namespace App\Livewire;

use App\Models\Company;
use App\Models\NotaFiscal;
use App\Services\Sefaz\ConsultaChaveService;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\Locked;
use Livewire\Component;

/**
 * Consulta de NF-e pela chave de acesso, digitada ou lida por leitor de
 * código de barras. O leitor se comporta como teclado: emite os 44 dígitos
 * em rajada e finaliza com Enter — por isso a tela dispara a consulta tanto
 * no Enter quanto ao completar 44 dígitos.
 */
class ConsultaChave extends Component
{
    public string $chave = '';

    /** Preenchido só depois de uma consulta bem-sucedida. */
    #[Locked]
    public ?int $notaId = null;

    #[Locked]
    public string $origem = '';   // local | sefaz

    #[Locked]
    public string $aviso = '';

    public bool $consultado = false;

    /**
     * Quando true, o master escolhe em nome de qual empresa consultar —
     * a consulta usa o certificado digital dela.
     */
    public bool $global = false;

    public ?int $companyId = null;

    public function updatedCompanyId(): void
    {
        $this->reset('notaId', 'origem', 'aviso', 'consultado');
        $this->resetErrorBag();
    }

    /**
     * Empresa em nome de quem a consulta é feita. Fora do modo global é
     * sempre a do próprio usuário — nunca uma vinda do navegador.
     */
    private function empresa(): ?Company
    {
        // companyId vem do navegador. Para quem não é master ele é ignorado —
        // a consulta sempre recai sobre a própria empresa. A tela global já é
        // barrada pela rota; isto é a trava no próprio componente.
        if (! $this->global || ! auth()->user()->isMaster()) {
            return auth()->user()->company;
        }

        return $this->companyId ? Company::find($this->companyId) : null;
    }

    public function updatedChave(string $valor): void
    {
        // Leitores costumam anexar prefixos e sufixos; guardamos só os dígitos.
        $this->chave = substr(preg_replace('/\D/', '', $valor), 0, 44);

        // Nem todo leitor envia Enter no fim da leitura. Ao completar os 44
        // dígitos a consulta dispara sozinha — é o fluxo de bipar e pronto.
        if (strlen($this->chave) === 44 && ! $this->consultado) {
            $this->consultar(app(ConsultaChaveService::class));
        }
    }

    public function consultar(ConsultaChaveService $consulta): void
    {
        $this->reset('notaId', 'origem', 'aviso');
        $this->resetErrorBag();

        $chave = preg_replace('/\D/', '', $this->chave);

        if (! ConsultaChaveService::chaveValida($chave)) {
            $this->addError('chave', strlen($chave) === 44
                ? 'A chave tem 44 dígitos, mas o dígito verificador não confere. Confira a leitura.'
                : sprintf('Informe os 44 dígitos da chave de acesso. Você digitou %d.', strlen($chave)));

            return;
        }

        $company = $this->empresa();

        if (! $company) {
            $this->addError('chave', $this->global
                ? 'Escolha a empresa em nome de quem a consulta será feita.'
                : 'Sua conta não está vinculada a nenhuma empresa.');

            return;
        }

        $this->consultado = true;

        // 1) Acervo local — a nota provavelmente já veio pelo monitor.
        $local = $consulta->buscarLocal($company, $chave);

        if ($local && $local->tem_xml_completo) {
            $this->notaId = $local->id;
            $this->origem = 'local';
            $this->aviso = 'Nota encontrada no acervo da empresa.';

            return;
        }

        // 2) SEFAZ — busca ou completa o que só existe como resumo.
        $retorno = $consulta->consultarNaSefaz($company, $chave);

        if (! $retorno['ok']) {
            // O resumo local ainda é melhor que nada: mantém o que já temos.
            if ($local) {
                $this->notaId = $local->id;
                $this->origem = 'local';
                $this->aviso = $retorno['mensagem'];

                return;
            }

            $this->addError('chave', $retorno['mensagem']);

            return;
        }

        $this->notaId = $retorno['nota']->id;
        $this->origem = 'sefaz';
        $this->aviso = $retorno['mensagem'];
    }

    public function novaConsulta(): void
    {
        $this->reset('chave', 'notaId', 'origem', 'aviso', 'consultado');
        $this->resetErrorBag();
        $this->dispatch('focar-chave');
    }

    public function render(): View
    {
        return view('livewire.consulta-chave', [
            'nota' => $this->notaId
                ? NotaFiscal::with(['eventos' => fn ($q) => $q->orderByDesc('data_evento')])->find($this->notaId)
                : null,
            'empresas' => $this->global
                ? Company::ativas()->orderBy('razao_social')->get(['id', 'razao_social', 'cnpj', 'cert_path'])
                : collect(),
        ]);
    }
}
