/*
 * Glifos do texto (como o painel de glifos do Illustrator e do Corel): os
 * caracteres que a fonte tem além do teclado (acentos, símbolos, setas,
 * frações, os extras das fontes decorativas) e os recursos dela (floreios,
 * letras alternativas, ligaduras, estilos), ligados por `font-feature-settings`
 * na peça inteira. O servidor lê o arquivo da fonte (glifos-do-servidor.ts);
 * aqui ficam os nomes, os grupos e a conta do CSS, que valem no navegador e
 * na exportação (o mesmo HTML).
 */

export type RecursosDaLetra = Record<string, number>;

/* Os recursos que aparecem com nome (só os que a fonte tem). `padrao`: o navegador já liga sozinho. */
export const RECURSOS_DA_LETRA: Array<{ tag: string; nome: string; detalhe: string; padrao?: 1 }> = [
  { tag: "swsh", nome: "Floreios", detalhe: "Letras com rabisco (comuns nas fontes manuscritas)" },
  { tag: "cswh", nome: "Floreios no contexto", detalhe: "O floreio só onde cabe (começo e fim de palavra)" },
  { tag: "init", nome: "Letra inicial com floreio", detalhe: "A primeira letra da palavra muda" },
  { tag: "fina", nome: "Letra final com floreio", detalhe: "A última letra da palavra muda" },
  { tag: "salt", nome: "Letras alternativas", detalhe: "Outro desenho para algumas letras" },
  { tag: "dlig", nome: "Ligaduras especiais", detalhe: "Pares de letras desenhados juntos (ct, st, Th)" },
  { tag: "liga", nome: "Ligaduras comuns", detalhe: "fi, fl e ff juntos", padrao: 1 },
  { tag: "calt", nome: "Alternativas no contexto", detalhe: "A letra muda conforme a vizinha", padrao: 1 },
  { tag: "smcp", nome: "Versalete", detalhe: "Minúsculas viram maiúsculas pequenas" },
  { tag: "c2sc", nome: "Maiúsculas em versalete", detalhe: "Maiúsculas viram maiúsculas pequenas" },
  { tag: "onum", nome: "Números antigos", detalhe: "Números que sobem e descem, como letras" },
  { tag: "lnum", nome: "Números alinhados", detalhe: "Todos na altura das maiúsculas" },
  { tag: "tnum", nome: "Números da mesma largura", detalhe: "Bom para preço e tabela" },
  { tag: "frac", nome: "Frações", detalhe: "1/2 vira ½" },
  { tag: "ordn", nome: "Ordinais", detalhe: "1o vira 1º" },
  { tag: "sups", nome: "Sobrescrito", detalhe: "Letras e números pequenos no alto" },
  { tag: "zero", nome: "Zero cortado", detalhe: "Zero com risco (não confunde com O)" },
  ...Array.from({ length: 20 }, (_, i) => ({ tag: `ss${String(i + 1).padStart(2, "0")}`, nome: `Estilo ${i + 1}`, detalhe: "Um conjunto de letras alternativas da fonte" })),
];

/** O `font-feature-settings` da peça ("" quando não liga nada). Aspas simples: vai dentro do style="..." do HTML. */
export function cssDosRecursos(recursos: RecursosDaLetra | null | undefined): string {
  const partes = Object.entries(recursos || {})
    .filter(([tag, valor]) => /^[a-z0-9]{4}$/.test(tag) && Number.isInteger(valor) && valor >= 0 && valor <= 99)
    .map(([tag, valor]) => `'${tag}' ${valor}`);
  return partes.join(", ");
}

/** Os recursos que vêm do banco (só tag de 4 letras e número de 0 a 99); null quando não sobra nada. */
export function recursosLimpos(bruto: unknown): RecursosDaLetra | null {
  if (!bruto || typeof bruto !== "object") return null;
  const limpos = Object.fromEntries(Object.entries(bruto as Record<string, unknown>).filter(([tag, valor]) => /^[a-z0-9]{4}$/.test(tag) && Number.isInteger(valor) && (valor as number) >= 0 && (valor as number) <= 99)) as RecursosDaLetra;
  return Object.keys(limpos).length ? limpos : null;
}

/* Os grupos do painel (o primeiro que pega o caractere leva ele). */
export const GRUPOS_DE_GLIFOS: Array<{ nome: string; faixas: Array<[number, number]> }> = [
  { nome: "Extras da fonte", faixas: [[0xe000, 0xf8ff], [0xf0000, 0xffffd]] },
  { nome: "Símbolos e enfeites", faixas: [[0x2100, 0x214f], [0x2190, 0x23ff], [0x25a0, 0x27bf], [0x2900, 0x2bff], [0x1f300, 0x1faff], [0xa9, 0xa9], [0xae, 0xae], [0xb0, 0xb0], [0xa7, 0xa7], [0xb6, 0xb6]] },
  { nome: "Números, frações e moedas", faixas: [[0x2070, 0x209f], [0x2150, 0x218f], [0x20a0, 0x20cf], [0xb2, 0xb3], [0xb9, 0xb9], [0xbc, 0xbe], [0xa2, 0xa5], [0xaa, 0xaa], [0xba, 0xba], [0x2460, 0x24ff]] },
  { nome: "Pontuação", faixas: [[0xa1, 0xbf], [0x2000, 0x206f], [0xd7, 0xd7], [0xf7, 0xf7]] },
  { nome: "Letras com acento", faixas: [[0xc0, 0x24f], [0x1e00, 0x1eff]] },
  { nome: "Outros", faixas: [[0x250, 0x10ffff]] },
];

/** Os caracteres da fonte em grupos (sem o que já está no teclado e sem os de controle). */
export function glifosEmGrupos(caracteres: number[]): Array<{ nome: string; lista: number[] }> {
  const grupos = GRUPOS_DE_GLIFOS.map((g) => ({ nome: g.nome, lista: [] as number[] }));
  for (const c of caracteres) {
    if (c < 0xa1 || (c >= 0x300 && c <= 0x36f) || (c >= 0xfe00 && c <= 0xfe0f) || c === 0xad) continue;
    const i = GRUPOS_DE_GLIFOS.findIndex((g) => g.faixas.some(([de, ate]) => c >= de && c <= ate));
    if (i >= 0) grupos[i].lista.push(c);
  }
  return grupos.filter((g) => g.lista.length);
}
