"use client";

import { useEffect, useState } from "react";
import { ArrowLeft, Check, Copy, Loader2, QrCode, Trash2 } from "lucide-react";
import { CustomSelect } from "@/components/ui/custom-select";
import { Switch } from "@/components/ui/switch";
import { CashIcon, CreditCardIcon, PixIcon } from "@/components/icons/payment-icons";
import { formatMoney, formatMoneyInput } from "@/utils/formatters";
import { makeId, type PaymentMethod, type PaymentSplit } from "@/lib/pdv/carrinho";

/*
  Receber: o passo depois do cupom.

  A folha da direita vira este painel quando o caixa fecha a conta. Aqui cabe
  o que antes se espremia embaixo do carrinho: o meio de pagamento, a divisão
  entre meios, o troco, a conta onde o dinheiro cai — e o Pix pelo Mercado
  Pago, com o QR pequeno para o caixa acompanhar enquanto o grande está na
  tela do cliente.
*/

export type DisponibilidadeDoPagamento = {
  disponivel: boolean;
  /* Quem cobra, e como ele se chama na tela. Escrever "Mercado Pago" enquanto
     se cobra pelo Asaas e o tipo de mentira que so aparece quando o operador
     vai procurar o dinheiro no lugar errado. */
  provedor?: "mercado_pago" | "asaas" | null;
  provedorNome?: string | null;
  ambiente?: "sandbox" | "production";
  conta?: { id: string; nome: string } | null;
  motivo?: string;
};

export type CobrancaPix = {
  id: string;
  status: string;
  valor: number;
  qrCode: string | null;
  qrCodeBase64: string | null;
  expiraEm: string | null;
  aprovadaEm?: string | null;
  detalhe?: string | null;
  /* A foto da venda guardada na cobrança (só nas geradas pelo balcão novo). */
  foto?: { payload: Record<string, unknown>; resumo: Record<string, unknown> | null } | null;
};

export type FaseDoPix = "parado" | "preparando" | "gerando" | "aguardando" | "aprovado" | "falhou";

/* A NFC-e no balcão: ligada na configuração e escolhida para esta venda. */
export type NotaDaVenda = {
  disponivel: boolean;
  teste: boolean;
  emitir: boolean;
  documento: string;
};

function documentoDaNotaValido(documento: string) {
  const d = documento.replace(/\D/g, "");
  return d.length === 0 || d.length === 11 || d.length === 14;
}

const MEIOS: Array<{ method: PaymentMethod; rotulo: string; Icone: typeof PixIcon }> = [
  { method: "pix", rotulo: "PIX", Icone: PixIcon },
  { method: "card", rotulo: "CARTÃO", Icone: CreditCardIcon },
  { method: "cash", rotulo: "DINHEIRO", Icone: CashIcon },
];

function useContagem(expiraEm: string | null | undefined) {
  /* O "agora" mora no estado e o relógio o atualiza; a conta sai do
     vencimento de verdade. O primeiro tique é imediato, para o número não
     nascer velho quando o QR chega minutos depois de a tela abrir. */
  const [agora, setAgora] = useState(() => Date.now());
  useEffect(() => {
    if (!expiraEm) return;
    const bater = () => setAgora(Date.now());
    const primeiro = window.setTimeout(bater, 0);
    const relogio = window.setInterval(bater, 500);
    return () => {
      window.clearTimeout(primeiro);
      window.clearInterval(relogio);
    };
  }, [expiraEm]);
  if (!expiraEm) return null;
  return Math.max(0, Math.floor((new Date(expiraEm).getTime() - agora) / 1000));
}

function mmss(segundos: number | null) {
  if (segundos === null) return "--:--";
  return `${String(Math.floor(segundos / 60)).padStart(2, "0")}:${String(segundos % 60).padStart(2, "0")}`;
}

export function Receber({
  total,
  itemCount,
  payments,
  setPayments,
  paymentMethodOptions,
  quickMethod,
  applyQuickPayment,
  cashReceivedInput,
  setCashReceivedInput,
  change,
  paidTotal,
  missingPayment,
  overPayment,
  hasCashPayment,
  hasPixPayment,
  hasCardPayment,
  selectedBankAccountId,
  setSelectedBankAccountId,
  bankAccountOptions,
  selectedElectronicBankAccountId,
  setSelectedElectronicBankAccountId,
  electronicBankAccountOptions,
  requiresOpenCashSession,
  hasOpenCashSession,
  saleMessage,
  saleMessageTom,
  canFinalize,
  isFinalizing,
  aoConcluir,
  aoVoltar,
  mp,
  mpLigado,
  setMpLigado,
  usaMercadoPago,
  pixTotal,
  cobranca,
  faseDoPix,
  erroDoPix,
  aoCancelarPix,
  notaFiscal,
  setNotaFiscal,
}: {
  total: number;
  itemCount: number;
  payments: PaymentSplit[];
  setPayments: (atualizar: (antes: PaymentSplit[]) => PaymentSplit[]) => void;
  paymentMethodOptions: Array<{ value: string; label: string; icon?: React.ComponentType<{ size?: number; className?: string }> }>;
  quickMethod: PaymentMethod;
  applyQuickPayment: (metodo: PaymentMethod) => void;
  cashReceivedInput: string;
  setCashReceivedInput: (valor: string) => void;
  change: number;
  paidTotal: number;
  missingPayment: number;
  overPayment: number;
  hasCashPayment: boolean;
  hasPixPayment: boolean;
  hasCardPayment: boolean;
  selectedBankAccountId: string;
  setSelectedBankAccountId: (valor: string) => void;
  bankAccountOptions: Array<{ value: string; label: string }>;
  selectedElectronicBankAccountId: string;
  setSelectedElectronicBankAccountId: (valor: string) => void;
  electronicBankAccountOptions: Array<{ value: string; label: string }>;
  requiresOpenCashSession: boolean;
  hasOpenCashSession: boolean;
  saleMessage: string;
  saleMessageTom: "ok" | "erro";
  canFinalize: boolean;
  isFinalizing: boolean;
  aoConcluir: () => void;
  aoVoltar: () => void;
  mp: DisponibilidadeDoPagamento | null;
  mpLigado: boolean;
  setMpLigado: (valor: boolean) => void;
  usaMercadoPago: boolean;
  pixTotal: number;
  cobranca: CobrancaPix | null;
  faseDoPix: FaseDoPix;
  erroDoPix: string | null;
  aoCancelarPix: () => void;
  notaFiscal?: NotaDaVenda | null;
  setNotaFiscal?: (atualizar: (antes: NotaDaVenda) => NotaDaVenda) => void;
}) {
  const restante = useContagem(faseDoPix === "aguardando" ? cobranca?.expiraEm : null);
  const [copiado, setCopiado] = useState(false);
  const pixEmAndamento = faseDoPix === "preparando" || faseDoPix === "gerando" || faseDoPix === "aguardando";
  const pixPago = faseDoPix === "aprovado";
  /* Enquanto o QR está na tela, nada se mexe. Com o Pix já pago, o painel
     destrava: o dinheiro está preso a esta venda, e o caixa pode ajustar o
     resto (outra parte, desconto, item) e concluir. */
  const travado = pixEmAndamento;
  const pagoAs =
    pixPago && cobranca?.aprovadaEm
      ? new Date(cobranca.aprovadaEm).toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" })
      : null;

  async function copiarPix() {
    if (!cobranca?.qrCode) return;
    try {
      await navigator.clipboard.writeText(cobranca.qrCode);
      setCopiado(true);
      window.setTimeout(() => setCopiado(false), 1800);
    } catch {
      /* sem área de transferência, o QR continua na tela */
    }
  }

  const rotuloDoBotao = isFinalizing
    ? "Concluindo…"
    : pixPago
      ? "Concluir venda"
      : usaMercadoPago
        ? `Gerar Pix de ${formatMoney(pixTotal)}`
        : "Confirmar venda";

  return (
    <aside className="pdv-folha">
      <div className="pdv-cupom-topo">
        <button type="button" className="pdv-botao" onClick={aoVoltar} disabled={travado} title="Esc">
          <ArrowLeft size={14} />
          Cupom
        </button>
        <div className="text-right">
          <div className="pdv-eyebrow">Receber</div>
          <div className="text-[12px] font-semibold text-[var(--ks-color-text-soft)]">
            {itemCount} {itemCount === 1 ? "peça" : "peças"} · {formatMoney(total)}
          </div>
        </div>
      </div>

      <div className="pdv-pagamento-corpo">
        {pixEmAndamento || pixPago ? (
          <div className="pdv-qr">
            {faseDoPix === "aguardando" && cobranca ? (
              <>
                <div className="pdv-qr-imagem">
                  {cobranca.qrCodeBase64 ? (
                    // eslint-disable-next-line @next/next/no-img-element
                    <img
                      src={cobranca.qrCodeBase64.startsWith("data:") ? cobranca.qrCodeBase64 : `data:image/png;base64,${cobranca.qrCodeBase64}`}
                      alt="QR Code do Pix"
                    />
                  ) : (
                    <QrCode size={40} className="m-auto text-[var(--ks-color-text-soft)]" />
                  )}
                </div>
                <div className="pdv-qr-valor">{formatMoney(cobranca.valor)}</div>
                <div className={`pdv-qr-tempo ${restante !== null && restante <= 60 ? "pdv-qr-tempo-urgente" : ""}`}>
                  {restante === 0 ? "O código venceu" : `Vale por ${mmss(restante)}`}
                </div>
                <div className="pdv-qr-estado">
                  <Loader2 size={13} className="pdv-girando" />
                  Esperando o pagamento — a tela do cliente está com o QR grande
                </div>
                <div className="flex gap-2">
                  <button type="button" className="pdv-botao" onClick={copiarPix} disabled={!cobranca.qrCode}>
                    {copiado ? <Check size={14} /> : <Copy size={14} />}
                    {copiado ? "Copiado" : "Copiar código"}
                  </button>
                  <button type="button" className="pdv-botao pdv-botao-perigo" onClick={aoCancelarPix}>
                    Cancelar Pix
                  </button>
                </div>
              </>
            ) : pixPago ? (
              <>
                <div className="pdv-feito-check">
                  <Check size={26} />
                </div>
                <div className="pdv-qr-valor">{formatMoney(cobranca?.valor || pixTotal)}</div>
                <div className="pdv-qr-estado">
                  Pix pago{pagoAs ? ` às ${pagoAs}` : ""} pelo {mp?.provedorNome || "provedor"} — preso a esta venda.
                </div>
                <div className="pdv-qr-estado">
                  {isFinalizing ? (
                    <>
                      <Loader2 size={13} className="pdv-girando" />
                      Registrando a venda…
                    </>
                  ) : erroDoPix ? (
                    "A venda ainda não foi registrada. Ajuste o que faltar e conclua."
                  ) : (
                    "Confira o restante e conclua a venda."
                  )}
                </div>
              </>
            ) : (
              <>
                <Loader2 size={28} className="pdv-girando text-[var(--ks-color-primary)]" />
                <div className="pdv-qr-estado">
                  {faseDoPix === "preparando" ? "Preparando o pagamento…" : `Gerando o QR Code no ${mp?.provedorNome || "provedor"}…`}
                </div>
              </>
            )}
          </div>
        ) : null}

        {erroDoPix ? <div className="pdv-aviso pdv-aviso-erro">{erroDoPix}</div> : null}

        {!travado ? (
          <>
            <div>
              <div className="pdv-bloco-titulo">
                <span className="pdv-eyebrow">Meio de pagamento</span>
                <kbd>F8</kbd>
              </div>
              <div className="pdv-meios">
                {MEIOS.map(({ method, rotulo, Icone }) => (
                  <button
                    key={method}
                    type="button"
                    className={`pdv-meio ${quickMethod === method ? "pdv-meio-ativo" : ""}`}
                    onClick={() => applyQuickPayment(method)}
                    disabled={pixPago && method === "pix"}
                    title={pixPago && method === "pix" ? "O Pix desta venda já foi pago" : undefined}
                  >
                    <Icone size={17} />
                    {rotulo}
                  </button>
                ))}
              </div>
            </div>

            <div className="pdv-divisoes">
              {payments.map((pagamento) => {
                const travada = pixPago && pagamento.method === "pix";
                return (
                <div
                  key={pagamento.id}
                  className={`pdv-divisao ${travada ? "pdv-divisao-travada" : ""}`}
                  title={travada ? "Valor já pago pelo Pix" : undefined}
                >
                  <CustomSelect
                    options={paymentMethodOptions}
                    value={pagamento.method}
                    onChange={(valor) =>
                      setPayments((antes) =>
                        antes.map((atual) => (atual.id === pagamento.id ? { ...atual, method: valor as PaymentMethod } : atual))
                      )
                    }
                    className="pdv-select-campo"
                    portal={false}
                    disabled={travada}
                  />
                  <input
                    readOnly={travada}
                    value={pagamento.amount_input}
                    onChange={(evento) =>
                      setPayments((antes) =>
                        antes.map((atual) =>
                          atual.id === pagamento.id ? { ...atual, amount_input: formatMoneyInput(evento.target.value) } : atual
                        )
                      )
                    }
                    className="pdv-campo pdv-campo-num"
                    placeholder="0,00"
                    aria-label="Valor"
                  />
                  <button
                    type="button"
                    className="pdv-lixeira"
                    disabled={payments.length === 1 || travada}
                    onClick={() => setPayments((antes) => antes.filter((atual) => atual.id !== pagamento.id))}
                    aria-label="Tirar esta parte"
                  >
                    <Trash2 size={13} />
                  </button>
                </div>
                );
              })}
              <button
                type="button"
                className="pdv-mais"
                onClick={() => setPayments((antes) => [...antes, { id: makeId(), method: quickMethod, amount_input: "" }])}
              >
                + Dividir em mais de um meio
              </button>
            </div>

            {hasCashPayment ? (
              <div className="pdv-troco">
                <div>
                  <label className="pdv-rotulo">Valor recebido em dinheiro</label>
                  <input
                    value={cashReceivedInput}
                    onChange={(evento) => setCashReceivedInput(formatMoneyInput(evento.target.value))}
                    placeholder="0,00"
                    className="pdv-campo pdv-campo-num"
                  />
                </div>
                <div className="self-end">
                  <div className="pdv-troco-valor">Troco {formatMoney(change)}</div>
                </div>
              </div>
            ) : null}

            {hasPixPayment && !pixPago ? (
              <div className={`pdv-mp ${mpLigado && mp?.disponivel ? "pdv-mp-ligado" : ""}`}>
                <div className="pdv-mp-texto">
                  <strong>Cobrar o Pix pelo {mp?.provedorNome || "provedor de pagamento"}</strong>
                  {mp?.disponivel ? (
                    <span>
                      O QR aparece na tela do cliente e a venda fecha sozinha quando o pagamento cair
                      {mp.conta ? ` na conta ${mp.conta.nome}` : ""}
                      {mp.ambiente === "sandbox" ? " (ambiente de testes)" : ""}.
                    </span>
                  ) : (
                    <span>{mp?.motivo || "Configure um provedor de pagamento em Configurações › Integrações para ligar."}</span>
                  )}
                </div>
                <Switch checked={Boolean(mpLigado && mp?.disponivel)} onCheckedChange={setMpLigado} disabled={!mp?.disponivel} />
              </div>
            ) : null}

            {notaFiscal?.disponivel && setNotaFiscal ? (
              <div className={`pdv-mp ${notaFiscal.emitir ? "pdv-mp-ligado" : ""}`}>
                <div className="pdv-mp-texto">
                  <strong>Emitir NFC-e{notaFiscal.teste ? " (teste)" : ""}</strong>
                  <span>
                    {notaFiscal.teste
                      ? "A nota sai em modo de teste, sem valor fiscal."
                      : "O cupom fiscal sai junto com a venda e gasta uma nota do pacote."}
                  </span>
                  {notaFiscal.emitir ? (
                    <>
                      <input
                        value={notaFiscal.documento}
                        onChange={(evento) => {
                          const valor = evento.target.value.replace(/[^\d./-]/g, "").slice(0, 18);
                          setNotaFiscal((antes) => ({ ...antes, documento: valor }));
                        }}
                        className="pdv-campo mt-2"
                        placeholder="CPF ou CNPJ na nota (opcional)"
                        inputMode="numeric"
                        aria-label="CPF ou CNPJ na nota"
                      />
                      {!documentoDaNotaValido(notaFiscal.documento) ? (
                        <span className="mt-1 text-[11px] font-semibold text-[var(--ks-color-status-danger)]">
                          CPF tem 11 números e CNPJ tem 14.
                        </span>
                      ) : null}
                    </>
                  ) : null}
                </div>
                <Switch checked={notaFiscal.emitir} onCheckedChange={(emitir) => setNotaFiscal((antes) => ({ ...antes, emitir }))} />
              </div>
            ) : null}

            <div className="pdv-conta">
              {hasCashPayment ? (
                <div className="pdv-conta-linha">
                  <span>Dinheiro em</span>
                  <CustomSelect
                    options={bankAccountOptions}
                    value={selectedBankAccountId}
                    onChange={setSelectedBankAccountId}
                    className="pdv-select-campo"
                    placeholder="Caixa físico"
                    portal={false}
                  />
                </div>
              ) : null}
              {hasCardPayment || (hasPixPayment && !(usaMercadoPago && mp?.conta)) ? (
                <div className="pdv-conta-linha">
                  <span>{hasCardPayment && hasPixPayment ? "Pix e cartão em" : hasCardPayment ? "Cartão em" : "Pix em"}</span>
                  <CustomSelect
                    options={electronicBankAccountOptions}
                    value={selectedElectronicBankAccountId}
                    onChange={setSelectedElectronicBankAccountId}
                    className="pdv-select-campo"
                    placeholder="Conta bancária"
                    portal={false}
                  />
                </div>
              ) : null}
            </div>

            <div className="pdv-resumo">
              <div>
                <span>Total</span>
                <strong>{formatMoney(total)}</strong>
              </div>
              <div>
                <span>Informado</span>
                <span>{formatMoney(paidTotal)}</span>
              </div>
              <div>
                <span>Falta</span>
                <strong style={{ color: missingPayment > 0.001 ? "var(--ks-color-status-danger)" : "var(--ks-color-status-success)" }}>
                  {formatMoney(missingPayment)}
                </strong>
              </div>
              {overPayment > 0.001 ? (
                <div>
                  <span>A mais</span>
                  <strong style={{ color: "var(--ks-color-status-warning)" }}>{formatMoney(overPayment)}</strong>
                </div>
              ) : null}
            </div>

            {hasCashPayment && !selectedBankAccountId ? (
              <div className="pdv-aviso">Escolha o caixa físico onde o dinheiro entra.</div>
            ) : null}
            {hasCardPayment && !selectedElectronicBankAccountId ? (
              <div className="pdv-aviso">Escolha a conta bancária onde o cartão cai.</div>
            ) : null}
            {hasPixPayment && !selectedElectronicBankAccountId && !(usaMercadoPago && mp?.conta) ? (
              <div className="pdv-aviso">Escolha a conta bancária onde o Pix cai.</div>
            ) : null}
            {overPayment > 0.001 ? (
              <div className="pdv-aviso">Os valores passam do total. Troco vai no campo “valor recebido”, não aqui.</div>
            ) : null}
            {requiresOpenCashSession && !hasOpenCashSession ? (
              <div className="pdv-aviso">Abra o caixa físico (menu Caixa, na barra de cima) para receber em dinheiro.</div>
            ) : null}
          </>
        ) : null}

        {saleMessage ? <div className={`pdv-aviso ${saleMessageTom === "ok" ? "pdv-aviso-ok" : "pdv-aviso-erro"}`}>{saleMessage}</div> : null}
      </div>

      <div className="pdv-pagamento-pe">
        {!pixEmAndamento ? (
          <button
            type="button"
            className={`pdv-receber ${pixPago ? "pdv-receber-verde" : ""}`}
            disabled={!canFinalize || isFinalizing}
            onClick={aoConcluir}
          >
            {rotuloDoBotao}
            <kbd>Enter</kbd>
          </button>
        ) : null}
      </div>
    </aside>
  );
}
