import { canonico } from "../confirmacao.ts";

/**
 * O que o assistente pode personalizar na conta, e as regras de cada coisa.
 *
 * São configurações que já existiam no painel (WhatsApp > Mensagens e
 * Orçamentos):
 *
 * - a mensagem do WhatsApp que acompanha o orçamento;
 * - a mensagem do WhatsApp que acompanha o andamento do pedido;
 * - as três da loja virtual: a dúvida sobre produto e o cabeçalho e o rodapé
 *   do pedido do carrinho (a loja as lê desde as Regras da loja, em
 *   apps/public/src/lib/loja/regras-da-loja.ts);
 * - a observação padrão, que aparece em todo orçamento, no PDF e no link.
 *
 * Tudo mora no perfil do dono da empresa, nas mesmas colunas que o painel lê.
 * Só regra, sem banco, para o teste ao lado rodar sozinho.
 */

export type TipoDePersonalizacao = "mensagem_do_whatsapp" | "observacao_do_orcamento";

type Marcador = { codigo: string; descricao: string; exemplo: string };

type DefinicaoDaMensagem = {
  /* A chave em `profiles.whatsapp_templates`. */
  chave: "quote_share" | "order_status" | "product_inquiry" | "cart_checkout_header" | "cart_checkout_footer";
  nome: string;
  titulo: string;
  /* O texto que vale quando a empresa não escreveu o seu. O mesmo do painel
     (dashboard/whatsapp) e de lib/whatsapp-templates-client.ts. */
  padrao: string;
  marcadores: Marcador[];
  /* A loja virtual lê esta mensagem: depois de gravar, ela é avisada. */
  daLoja: boolean;
  /* O aviso quando a mensagem fica sem {{link}} (null = não precisa de link). */
  avisoSemLink: string | null;
  /* Onde a mensagem vale e onde não vale, para a pessoa não se surpreender. */
  observacao: string | null;
};

export const MENSAGENS = {
  orcamento: {
    chave: "quote_share",
    nome: "orçamento",
    titulo: "Mensagem do orçamento no WhatsApp",
    padrao: "Olá! Segue o orçamento #{{numero_orcamento}}. Total: {{total}}.{{validade}} {{link}}",
    marcadores: [
      { codigo: "{{numero_orcamento}}", descricao: "o número do orçamento", exemplo: "42" },
      { codigo: "{{total}}", descricao: "o valor total", exemplo: "R$ 1.500,00" },
      { codigo: "{{validade}}", descricao: "a validade, já com espaço e ponto (fica vazio quando não há)", exemplo: " Validade: 15/03/2027." },
      {
        codigo: "{{condicoes}}",
        descricao: "as condições de pagamento, já com espaço (fica vazio quando não há)",
        exemplo: " Pagamento: entrada de 50% (R$ 750,00) na aprovação e saldo na entrega. Pix ou cartão de crédito.",
      },
      { codigo: "{{link}}", descricao: "o link do orçamento, onde o cliente vê e aprova", exemplo: "https://ktalogu.com.br/sua-loja/o/abc123" },
    ],
    daLoja: false,
    avisoSemLink: "A mensagem não tem {{link}}: o cliente não recebe o link para ver e aprovar o orçamento.",
    observacao: null,
  },
  pedido: {
    chave: "order_status",
    nome: "andamento do pedido",
    titulo: "Mensagem do andamento do pedido no WhatsApp",
    padrao: "Olá! Segue atualização sobre seu pedido #{{numero_pedido}}. Status atual: *{{status}}*. Acompanhe o progresso em tempo real: {{link}}",
    marcadores: [
      { codigo: "{{numero_pedido}}", descricao: "o número do pedido", exemplo: "15" },
      { codigo: "{{status}}", descricao: "a situação atual do pedido", exemplo: "Em produção" },
      { codigo: "{{link}}", descricao: "o link de acompanhamento do pedido", exemplo: "https://ktalogu.com.br/sua-loja/status/abc123" },
    ],
    daLoja: false,
    avisoSemLink: "A mensagem não tem {{link}}: o cliente não recebe o link para acompanhar o pedido.",
    observacao: null,
  },
  produto: {
    chave: "product_inquiry",
    nome: "dúvida sobre produto",
    titulo: "Mensagem de dúvida sobre produto na loja",
    padrao: "Olá! Tenho interesse no produto {{nome_produto}}",
    marcadores: [{ codigo: "{{nome_produto}}", descricao: "o nome do produto", exemplo: "Adesivo Vinílico Premium" }],
    daLoja: true,
    avisoSemLink: null,
    observacao: "É o texto que o cliente manda ao tocar no WhatsApp da página do produto, na loja virtual.",
  },
  cabecalho_do_pedido: {
    chave: "cart_checkout_header",
    nome: "cabeçalho do pedido da loja",
    titulo: "Cabeçalho do pedido da loja no WhatsApp",
    padrao: "*Novo Pedido*",
    marcadores: [],
    daLoja: true,
    avisoSemLink: null,
    observacao:
      "A primeira linha do pedido que o carrinho da loja manda pelo WhatsApp; o número do pedido entra logo depois, sozinho. Vale para pedido com preço; o pedido de orçamento usa um texto fixo.",
  },
  rodape_do_pedido: {
    chave: "cart_checkout_footer",
    nome: "rodapé do pedido da loja",
    titulo: "Rodapé do pedido da loja no WhatsApp",
    padrao: "{{resumo_itens}}\n\n{{subtotal}}\n{{desconto}}\n*Total: {{total}}*",
    marcadores: [
      { codigo: "{{resumo_itens}}", descricao: "a lista dos itens (sem ele, os itens vão acima do rodapé)", exemplo: "2x Adesivo Vinílico - R$ 50,00\n1x Papel Fotográfico - R$ 25,00" },
      { codigo: "{{subtotal}}", descricao: "o subtotal, já com a palavra Subtotal", exemplo: "Subtotal: R$ 75,00" },
      { codigo: "{{desconto}}", descricao: "o desconto do cupom (fica vazio sem cupom)", exemplo: "Desconto (PROMO10): -R$ 7,50" },
      { codigo: "{{total}}", descricao: "o valor total", exemplo: "R$ 67,50" },
    ],
    daLoja: true,
    avisoSemLink: null,
    observacao: "O fim do pedido que o carrinho da loja manda pelo WhatsApp, depois dos dados do cliente. Vale para pedido com preço; o pedido de orçamento usa um texto fixo.",
  },
} as const satisfies Record<string, DefinicaoDaMensagem>;

export type QualMensagem = keyof typeof MENSAGENS;

export const QUAIS_MENSAGENS = Object.keys(MENSAGENS) as QualMensagem[];

/** O nome que a pessoa usa ("orçamento", "andamento do pedido") vira a chave daqui. */
export function qualMensagemPeloNome(nome: unknown): QualMensagem | null {
  const texto = String(nome ?? "").trim().toLocaleLowerCase("pt-BR");
  return QUAIS_MENSAGENS.find((qual) => MENSAGENS[qual].nome === texto || qual === texto) ?? null;
}

export const TAMANHO_DA_MENSAGEM = 1000;
export const TAMANHO_DA_OBSERVACAO = 2000;

function objeto(valor: unknown): Record<string, unknown> {
  return valor && typeof valor === "object" && !Array.isArray(valor) ? (valor as Record<string, unknown>) : {};
}

/** O texto que a empresa escreveu para esta mensagem; `null` quando vale o padrão. */
export function lerMensagem(templates: unknown, qual: QualMensagem): string | null {
  const salvo = objeto(templates)[MENSAGENS[qual].chave];
  return typeof salvo === "string" && salvo.trim() ? salvo : null;
}

/** O texto que vai de fato para o cliente. */
export function textoEfetivo(qual: QualMensagem, salvo: string | null): string {
  return salvo ?? MENSAGENS[qual].padrao;
}

/**
 * O objeto de mensagens com esta trocada. `null` volta ao padrão (a chave sai
 * do objeto). As outras mensagens ficam como estavam.
 */
export function comMensagem(templates: unknown, qual: QualMensagem, texto: string | null): Record<string, unknown> {
  const novo: Record<string, unknown> = { ...objeto(templates) };
  if (texto === null) delete novo[MENSAGENS[qual].chave];
  else novo[MENSAGENS[qual].chave] = texto;
  return novo;
}

export type Conferencia = { ok: true; avisos: string[] } | { ok: false; erro: string };

/** Confere o texto que o assistente quer gravar numa mensagem. */
export function conferirMensagem(qual: QualMensagem, texto: string): Conferencia {
  const definicao = MENSAGENS[qual];
  const limpo = texto.trim();
  if (!limpo) return { ok: false, erro: "A mensagem não pode ficar vazia. Para voltar ao texto do sistema, use voltar_ao_padrao." };
  if (limpo.length > TAMANHO_DA_MENSAGEM) return { ok: false, erro: `A mensagem passou do tamanho máximo (${TAMANHO_DA_MENSAGEM} letras).` };

  const aceitos = definicao.marcadores.map((marcador) => marcador.codigo) as string[];
  const usados = [...new Set(limpo.match(/\{\{[^{}]*\}\}/g) ?? [])];
  const estranhos = usados.filter((usado) => !aceitos.includes(usado));
  if (estranhos.length) {
    return {
      ok: false,
      erro: `${estranhos.join(", ")} não existe nesta mensagem, e ia chegar assim mesmo, entre chaves, para o cliente. Os que existem: ${aceitos.join(", ")}.`,
    };
  }
  /* Chave aberta e não fechada (ou o contrário) também chega torta ao cliente. */
  if (/\{\{|\}\}/.test(limpo.replace(/\{\{[^{}]*\}\}/g, ""))) {
    return { ok: false, erro: "Há chaves {{ }} sem par na mensagem. Use os marcadores exatamente como estão escritos." };
  }

  const avisos: string[] = [];
  if (definicao.avisoSemLink && !usados.includes("{{link}}")) avisos.push(definicao.avisoSemLink);
  if (qual === "rodape_do_pedido" && !usados.includes("{{total}}")) {
    avisos.push("O rodapé não tem {{total}}: o pedido chega à loja sem o valor total.");
  }
  return { ok: true, avisos };
}

/** A mensagem como o cliente vai ler, com valores de exemplo no lugar dos marcadores. */
export function exemploDaMensagem(qual: QualMensagem, texto: string): string {
  let exemplo = texto;
  for (const marcador of MENSAGENS[qual].marcadores) exemplo = exemplo.split(marcador.codigo).join(marcador.exemplo);
  return exemplo;
}

export type Observacao = { texto: string | null; ligada: boolean };

export function lerObservacao(perfil: { quote_default_notes?: unknown; quote_default_notes_enabled?: unknown } | null | undefined): Observacao {
  const texto = typeof perfil?.quote_default_notes === "string" && perfil.quote_default_notes.trim() ? perfil.quote_default_notes : null;
  return { texto, ligada: perfil?.quote_default_notes_enabled === true };
}

/** As colunas do perfil para uma observação. */
export function colunasDaObservacao(observacao: Observacao) {
  return { quote_default_notes: observacao.texto, quote_default_notes_enabled: observacao.ligada };
}

/**
 * O que a pessoa pediu, aplicado sobre a observação de hoje. Texto novo sem
 * dizer se liga já liga: quem escreve uma observação quer que ela apareça.
 */
export function observacaoPedida(atual: Observacao, pedido: { texto?: string; ligada?: boolean }): { ok: true; observacao: Observacao } | { ok: false; erro: string } {
  const texto = pedido.texto !== undefined ? pedido.texto.trim() : atual.texto;
  if (pedido.texto !== undefined && texto && texto.length > TAMANHO_DA_OBSERVACAO) {
    return { ok: false, erro: `A observação passou do tamanho máximo (${TAMANHO_DA_OBSERVACAO} letras).` };
  }
  const ligada = pedido.ligada ?? (pedido.texto !== undefined ? true : atual.ligada);
  if (ligada && !texto) return { ok: false, erro: "Para ligar a observação padrão, informe o texto dela." };
  return { ok: true, observacao: { texto: texto || null, ligada } };
}

/** Dois valores guardados são o mesmo? (A ordem das chaves não conta.) */
export function mesmoValor(a: unknown, b: unknown): boolean {
  return canonico(a ?? null) === canonico(b ?? null);
}

/** O valor guardado, em uma linha, para a lista do painel e a prévia de desfazer. */
export function descreverValor(tipo: TipoDePersonalizacao, valor: unknown, maximo = 140): string {
  const curto = (texto: string) => {
    const linha = texto.replace(/\s+/g, " ").trim();
    return linha.length > maximo ? `${linha.slice(0, maximo)}…` : linha;
  };
  if (tipo === "mensagem_do_whatsapp") return typeof valor === "string" && valor.trim() ? `“${curto(valor)}”` : "o texto padrão do sistema";
  const observacao = lerObservacao({
    quote_default_notes: objeto(valor).texto,
    quote_default_notes_enabled: objeto(valor).ligada,
  });
  if (!observacao.texto) return observacao.ligada ? "ligada, sem texto" : "desligada";
  return `${observacao.ligada ? "" : "desligada: "}“${curto(observacao.texto)}”`;
}

/** O título de uma personalização, para o registro e a lista do painel. */
export function tituloDe(tipo: TipoDePersonalizacao, alvo: string | null): string {
  if (tipo === "observacao_do_orcamento") return "Observação padrão do orçamento";
  const qual = QUAIS_MENSAGENS.find((chave) => MENSAGENS[chave].chave === alvo);
  return qual ? MENSAGENS[qual].titulo : "Mensagem do WhatsApp";
}
