/**
 * Subject Template Service — extracts reusable templates from existing
 * registry subjects and provides filtering/assembly utilities.
 *
 * Also provides seed templates per document type so the autocomplete
 * is useful from the very first entry.
 *
 * Pure functions, no React or side effects.
 */

import type { RegistryDirection } from "../types";

// ── Types ──

export type TemplateFieldType = "nr" | "an" | "detalii" | "proiect" | "text";

export interface TemplateField {
  id: string; // "f0", "f1", ...
  name: string; // "nr", "an", "detalii", "proiect"
  placeholder: string; // Romanian label
  width: string; // Tailwind width class
  fieldType?: TemplateFieldType;
  defaultValue?: string;
}

export interface TemplateToken {
  type: "static" | "field";
  value: string; // literal text for static, empty for fields
  field?: TemplateField;
}

export interface SubjectTemplate {
  id: string;
  pattern: string; // "Cerere CU nr. {nr}/{an} — {proiect}"
  tokens: TemplateToken[];
  fields: TemplateField[];
  frequency: number;
  exampleSubject: string;
  /** Whether this is a predefined seed template (not learned from DB) */
  isSeed?: boolean;
}

// ── Internal helpers ──

/** Simple hash for template deduplication */
function hashPattern(s: string): string {
  let h = 0;
  for (let i = 0; i < s.length; i++) {
    h = ((h << 5) - h + s.charCodeAt(i)) | 0;
  }
  return `t${Math.abs(h).toString(36)}`;
}

/**
 * Tokenize a subject into static text + variable field segments.
 *
 * Strategy: scan left-to-right, replacing recognized variable patterns with
 * field tokens while keeping everything else as static text.
 */
function tokenize(subject: string): TemplateToken[] {
  const tokens: TemplateToken[] = [];
  let fieldIdx = 0;

  // First check for a separator split (— or – or - with spaces)
  const sepMatch = subject.match(/^(.+?)\s([—–])\s(.+)$/);

  if (sepMatch) {
    const left = sepMatch[1]!;
    const sep = sepMatch[2]!;
    const right = sepMatch[3]!;

    // Tokenize the left part (may contain nr/an)
    const leftTokens = tokenizeSegment(left, fieldIdx);
    tokens.push(...leftTokens.tokens);
    fieldIdx = leftTokens.nextIdx;

    // Add separator as static
    tokens.push({ type: "static", value: ` ${sep} ` });

    // Right side is always a "detalii" field
    tokens.push({
      type: "field",
      value: "",
      field: {
        id: `f${fieldIdx}`,
        name: "detalii",
        placeholder: "detalii...",
        width: "flex-1 min-w-32",
        fieldType: "detalii",
      },
    });
  } else {
    // No separator — tokenize the whole thing
    const result = tokenizeSegment(subject, fieldIdx);
    tokens.push(...result.tokens);
  }

  return tokens;
}

/**
 * Tokenize a segment (no separator) by replacing number patterns.
 */
function tokenizeSegment(
  segment: string,
  startIdx: number,
): { tokens: TemplateToken[]; nextIdx: number } {
  const tokens: TemplateToken[] = [];
  let idx = startIdx;

  // Combined regex: match year (4-digit 20xx) or other numbers (1-6 digits)
  const numPattern = /\b(20\d{2})\b|\b(\d{1,6})\b/g;

  let lastEnd = 0;
  let match: RegExpExecArray | null;

  while ((match = numPattern.exec(segment)) !== null) {
    // Static text before this match
    if (match.index > lastEnd) {
      tokens.push({ type: "static", value: segment.slice(lastEnd, match.index) });
    }

    const isYear = match[1] !== undefined;
    const ft: TemplateFieldType = isYear ? "an" : "nr";
    tokens.push({
      type: "field",
      value: "",
      field: {
        id: `f${idx}`,
        name: isYear ? "an" : "nr",
        placeholder: isYear ? "an" : "nr.",
        width: isYear ? "w-16" : "w-14",
        fieldType: ft,
      },
    });
    idx++;
    lastEnd = match.index + match[0].length;
  }

  // Trailing static text
  if (lastEnd < segment.length) {
    tokens.push({ type: "static", value: segment.slice(lastEnd) });
  }

  // If no fields found, the whole segment is a single static token
  if (tokens.length === 0) {
    tokens.push({ type: "static", value: segment });
  }

  return { tokens, nextIdx: idx };
}

/**
 * Build the pattern string from tokens for grouping/display.
 * E.g. "Cerere CU nr. {nr}/{an} — {detalii}"
 */
function buildPattern(tokens: TemplateToken[]): string {
  return tokens
    .map((t) => (t.type === "static" ? t.value : `{${t.field!.name}}`))
    .join("");
}

// ── Seed template builder ──

const CURRENT_YEAR = new Date().getFullYear().toString();

/**
 * Build a seed SubjectTemplate from a pattern string.
 * Parses `{fieldName}` placeholders into tokens/fields.
 */
function seedTemplate(pattern: string, example: string): SubjectTemplate {
  const tokens: TemplateToken[] = [];
  const fields: TemplateField[] = [];
  let fIdx = 0;

  // Split pattern by {fieldName} placeholders
  const parts = pattern.split(/(\{[^}]+\})/);
  for (const part of parts) {
    if (!part) continue;
    const fieldMatch = part.match(/^\{(\w+)\}$/);
    if (fieldMatch) {
      const name = fieldMatch[1]!;
      const ft = resolveFieldType(name);
      const field: TemplateField = {
        id: `f${fIdx}`,
        name,
        placeholder: fieldPlaceholder(ft),
        width: fieldWidth(ft),
        fieldType: ft,
        defaultValue: ft === "an" ? CURRENT_YEAR : undefined,
      };
      fields.push(field);
      tokens.push({ type: "field", value: "", field });
      fIdx++;
    } else {
      tokens.push({ type: "static", value: part });
    }
  }

  return {
    id: hashPattern(pattern),
    pattern,
    tokens,
    fields,
    frequency: 0,
    exampleSubject: example,
    isSeed: true,
  };
}

function resolveFieldType(name: string): TemplateFieldType {
  if (name === "nr") return "nr";
  if (name === "an") return "an";
  if (name === "proiect") return "proiect";
  if (name === "detalii") return "detalii";
  return "text";
}

function fieldPlaceholder(ft: TemplateFieldType): string {
  switch (ft) {
    case "nr": return "nr.";
    case "an": return "an";
    case "proiect": return "proiect...";
    case "detalii": return "detalii...";
    case "text": return "text...";
  }
}

function fieldWidth(ft: TemplateFieldType): string {
  switch (ft) {
    case "nr": return "w-14";
    case "an": return "w-16";
    case "proiect": return "flex-1 min-w-32";
    case "detalii": return "flex-1 min-w-32";
    case "text": return "flex-1 min-w-24";
  }
}

// ── Seed Templates Catalog ──

const SEED_TEMPLATES: Record<string, SubjectTemplate[]> = {
  cerere: [
    // Cereri emitere acte
    seedTemplate("Cerere pentru emiterea CU — {proiect}", "Cerere pentru emiterea CU — Farmacie Str. Exemplu"),
    seedTemplate("Cerere pentru emiterea AC — {proiect}", "Cerere pentru emiterea AC — Locuinta P+1E"),
    seedTemplate("Cerere pentru eliberarea certificatului de {detalii} — {proiect}", "Cerere pentru eliberarea certificatului de urbanism — Bloc rezidential"),
    // Cereri prelungire
    seedTemplate("Cerere pentru prelungirea valabilitatii CU nr. {nr}/{an} — {proiect}", "Cerere pentru prelungirea valabilitatii CU nr. 78/2026 — Bloc D4"),
    seedTemplate("Cerere pentru prelungirea valabilitatii AC nr. {nr}/{an} — {proiect}", "Cerere pentru prelungirea valabilitatii AC nr. 90/2026 — Hala industriala"),
    // Cereri completari / corectii
    seedTemplate("Cerere completare documentatie nr. {nr}/{an} — {proiect}", "Cerere completare documentatie nr. 33/2026 — Bloc rezidential"),
    seedTemplate("Cerere pentru indreptarea erorilor materiale — {proiect}", "Cerere pentru indreptarea erorilor materiale — Cladire birouri"),
    // Cereri diverse
    seedTemplate("Cerere inaintare dispozitie de santier — {proiect}", "Cerere inaintare dispozitie de santier — Locuinta P+1E"),
    seedTemplate("Cerere aviz {detalii} — {proiect}", "Cerere aviz ISU — Gradinita nr. 3"),
    seedTemplate("Cerere racordare {detalii} — {proiect}", "Cerere racordare gaz — Bloc rezidential"),
  ],
  aviz: [
    // Acte administrative primite (intrat)
    seedTemplate("CU nr. {nr}/{an} — {proiect}", "CU nr. 312/2026 — Farmacie Str. Exemplu"),
    seedTemplate("AC nr. {nr}/{an} — {proiect}", "AC nr. 89/2026 — Locuinta P+1E"),
    seedTemplate("Prelungire CU nr. {nr}/{an} — {proiect}", "Prelungire CU nr. 78/2026 — Bloc D4"),
    seedTemplate("Prelungire AC nr. {nr}/{an} — {proiect}", "Prelungire AC nr. 90/2026 — Hala industriala"),
    seedTemplate("Aviz ISU nr. {nr}/{an} — {proiect}", "Aviz ISU nr. 55/2026 — Cladire birouri"),
    seedTemplate("Aviz DSP nr. {nr}/{an} — {proiect}", "Aviz DSP nr. 14/2026 — Gradinita nr. 3"),
    seedTemplate("Aviz Mediu nr. {nr}/{an} — {proiect}", "Aviz Mediu nr. 22/2026 — Hala logistica"),
    seedTemplate("Aviz APM nr. {nr}/{an} — {proiect}", "Aviz APM nr. 8/2026 — PUZ Zona centrala"),
    seedTemplate("Aviz racordare {detalii} nr. {nr}/{an} — {proiect}", "Aviz racordare gaz nr. 31/2026 — Locuinta P+1E"),
    seedTemplate("Aviz {detalii} nr. {nr}/{an} — {proiect}", "Aviz Electrica nr. 44/2026 — Bloc rezidential"),
    seedTemplate("Aviz de oportunitate nr. {nr}/{an} — {proiect}", "Aviz de oportunitate nr. 12/2026 — PUZ Zona centrala"),
    seedTemplate("Acord unic nr. {nr}/{an} — {proiect}", "Acord unic nr. 67/2026 — Cladire birouri"),
    // Solicitari avize (iesit)
    seedTemplate("Solicitare aviz {detalii} — {proiect}", "Solicitare aviz DSP — Gradinita nr. 3"),
    seedTemplate("Solicitare CU — {proiect}", "Solicitare CU — Locuinta unifamiliala"),
    seedTemplate("Solicitare AC — {proiect}", "Solicitare AC — Cladire birouri"),
  ],
  contract: [
    seedTemplate("Contract nr. {nr}/{an} — {proiect}", "Contract nr. 15/2026 — Proiectare locuinta"),
    seedTemplate("Contract prestari servicii nr. {nr}/{an} — {proiect}", "Contract prestari servicii nr. 22/2026 — Studiu geo"),
    seedTemplate("Contract proiectare nr. {nr}/{an} — {proiect}", "Contract proiectare nr. 10/2026 — Bloc rezidential"),
    seedTemplate("Act aditional nr. {nr} la contract {detalii}", "Act aditional nr. 2 la contract 15/2026"),
    seedTemplate("PV predare-primire nr. {nr}/{an} — {proiect}", "PV predare-primire nr. 4/2026 — Cladire birouri"),
  ],
  oferta: [
    seedTemplate("Oferta proiectare {detalii} — {proiect}", "Oferta proiectare DTAC+PT — Bloc rezidential"),
    seedTemplate("Oferta nr. {nr}/{an} — {proiect}", "Oferta nr. 8/2026 — Mansardare bloc"),
  ],
  factura: [
    seedTemplate("Factura nr. {nr}/{an} — {proiect}", "Factura nr. 102/2026 — Farmacie Str. Exemplu"),
    seedTemplate("Factura proforma nr. {nr}/{an} — {proiect}", "Factura proforma nr. 5/2026 — Studiu geo"),
  ],
  scrisoare: [
    seedTemplate("Adresa nr. {nr}/{an} — {detalii}", "Adresa nr. 45/2026 — Raspuns solicitare informatii"),
    seedTemplate("Adresa {detalii} — {proiect}", "Adresa raspuns completari — Bloc rezidential"),
    seedTemplate("Adeverinta {detalii} nr. {nr}/{an}", "Adeverinta stagiu practica nr. 3/2026"),
    seedTemplate("Raspuns completari nr. {nr}/{an} — {proiect}", "Raspuns completari nr. 33/2026 — Bloc rezidential"),
    seedTemplate("Somatie {detalii} — {proiect}", "Somatie plata factura — Cladire birouri"),
    seedTemplate("Invitatie {detalii} — {proiect}", "Invitatie sedinta receptie — Cladire birouri"),
  ],
  "nota-de-comanda": [
    seedTemplate("Nota de comanda nr. {nr}/{an} — {proiect}", "Nota de comanda nr. 7/2026 — Instalatii electrice"),
    seedTemplate("Comanda {detalii} — {proiect}", "Comanda materiale — Santier Bloc A"),
  ],
  raport: [
    seedTemplate("Raport {detalii} — {proiect}", "Raport expertiza tehnica — Consolidare bloc"),
    seedTemplate("Memoriu justificativ — {proiect}", "Memoriu justificativ — Locuinta P+1E"),
    seedTemplate("Memoriu justificativ {detalii} — {proiect}", "Memoriu justificativ arhitectura — Bloc rezidential"),
    seedTemplate("Studiu geotehnic {detalii} — {proiect}", "Studiu geotehnic preliminar — Hala logistica"),
    seedTemplate("Studiu de fezabilitate — {proiect}", "Studiu de fezabilitate — Reabilitare scoala"),
    seedTemplate("Raport nr. {nr}/{an} — {proiect}", "Raport nr. 3/2026 — Audit energetic"),
    seedTemplate("Expertiza tehnica nr. {nr}/{an} — {proiect}", "Expertiza tehnica nr. 7/2026 — Consolidare bloc"),
    seedTemplate("RTE nr. {nr}/{an} — {proiect}", "RTE nr. 12/2026 — Reabilitare termica bloc"),
    seedTemplate("Audit energetic nr. {nr}/{an} — {proiect}", "Audit energetic nr. 4/2026 — Bloc C3"),
    seedTemplate("Caiet de sarcini — {proiect}", "Caiet de sarcini — Instalatii electrice"),
  ],
  "proces-verbal": [
    seedTemplate("PV receptie nr. {nr}/{an} — {proiect}", "PV receptie nr. 5/2026 — Cladire birouri"),
    seedTemplate("PV receptie la terminarea lucrarilor nr. {nr}/{an} — {proiect}", "PV receptie la terminarea lucrarilor nr. 2/2026 — Bloc D4"),
    seedTemplate("PV receptie finala nr. {nr}/{an} — {proiect}", "PV receptie finala nr. 1/2026 — Hala logistica"),
    seedTemplate("Proces verbal {detalii} nr. {nr}/{an} — {proiect}", "Proces verbal inspectie santier nr. 3/2026 — Bloc rezidential"),
    seedTemplate("PV predare documentatie — {proiect}", "PV predare documentatie — Locuinta P+1E"),
    seedTemplate("PV constatare {detalii} — {proiect}", "PV constatare neconformitati — Cladire birouri"),
  ],
  notificare: [
    seedTemplate("Notificare incepere lucrari — {proiect}", "Notificare incepere lucrari — Locuinta P+1E"),
    seedTemplate("Notificare finalizare lucrari — {proiect}", "Notificare finalizare lucrari — Bloc rezidential"),
    seedTemplate("Notificare {detalii} — {proiect}", "Notificare reluare lucrari — Hala industriala"),
    seedTemplate("Notificare nr. {nr}/{an} — {proiect}", "Notificare nr. 7/2026 — Cladire birouri"),
    seedTemplate("Instiintare {detalii} — {proiect}", "Instiintare incepere executie — Bloc D4"),
    seedTemplate("Instiintare ISC — {proiect}", "Instiintare ISC — Gradinita nr. 3"),
  ],
  comunicare: [
    seedTemplate("Comunicare {detalii} — {proiect}", "Comunicare rezultat analiza — Bloc rezidential"),
    seedTemplate("Comunicare nr. {nr}/{an} — {proiect}", "Comunicare nr. 18/2026 — Farmacie Str. Exemplu"),
    seedTemplate("Comunicare completari necesare — {proiect}", "Comunicare completari necesare — Locuinta P+1E"),
    seedTemplate("Comunicare respingere cerere — {proiect}", "Comunicare respingere cerere — Hala industriala"),
    seedTemplate("Comunicare {detalii} nr. {nr}/{an}", "Comunicare programare nr. 5/2026"),
  ],
  "apel-telefonic": [
    seedTemplate("Convorbire {detalii} — {proiect}", "Convorbire primarie avize — Bloc D4"),
    seedTemplate("Apel {detalii} — {proiect}", "Apel ISU programare — Gradinita nr. 3"),
  ],
  videoconferinta: [
    seedTemplate("Sedinta {detalii} — {proiect}", "Sedinta coordonare proiectare — Bloc rezidential"),
    seedTemplate("Videoconferinta {detalii} — {proiect}", "Videoconferinta revizie PT — Hala industriala"),
  ],
  altele: [
    seedTemplate("Documentatie {detalii} — {proiect}", "Documentatie PAC+DDE — Locuinta P+M"),
    seedTemplate("Referat verificare nr. {nr}/{an} — {proiect}", "Referat verificare nr. 11/2026 — Locuinta P+1E"),
    seedTemplate("Memoriu tehnic — {proiect}", "Memoriu tehnic — Hala industriala"),
    seedTemplate("Decizie {detalii} nr. {nr}/{an}", "Decizie etapizare nr. 2/2026"),
    seedTemplate("Borderou {detalii} — {proiect}", "Borderou piese scrise — Cladire birouri"),
    seedTemplate("Fisa tehnica {detalii} — {proiect}", "Fisa tehnica echipament HVAC — Bloc rezidential"),
    seedTemplate("Tema de proiectare — {proiect}", "Tema de proiectare — Locuinta unifamiliala"),
    seedTemplate("Deviz general — {proiect}", "Deviz general — Reabilitare scoala"),
    seedTemplate("Conventie {detalii} nr. {nr}/{an}", "Conventie colaborare nr. 2/2026"),
  ],
};

// ── Dynamic Placeholders ──

const SUBJECT_PLACEHOLDERS_MAP: Record<string, Record<string, string>> = {
  cerere: {
    intrat: "ex: Cerere completare documentatie — Proiect X",
    iesit: "ex: Cerere pentru emiterea CU — Proiect X",
  },
  aviz: {
    intrat: "ex: CU nr. 312/2026 — Proiect X",
    iesit: "ex: Solicitare aviz DSP — Proiect X",
  },
  contract: {
    intrat: "ex: Contract nr. 15/2026 — Proiect X",
    iesit: "ex: Contract prestari servicii nr. 22/2026 — Proiect X",
  },
  oferta: {
    intrat: "ex: Oferta nr. 8/2026 — Proiect X",
    iesit: "ex: Oferta proiectare DTAC+PT — Proiect X",
  },
  factura: {
    intrat: "ex: Factura nr. 102/2026 — Proiect X",
    iesit: "ex: Factura proforma nr. 5/2026 — Proiect X",
  },
  scrisoare: {
    intrat: "ex: Adresa nr. 45/2026 — Raspuns informatii",
    iesit: "ex: Adresa raspuns completari — Proiect X",
  },
  "nota-de-comanda": {
    intrat: "ex: Nota de comanda nr. 7/2026 — Proiect X",
    iesit: "ex: Comanda materiale — Proiect X",
  },
  raport: {
    intrat: "ex: Expertiza tehnica nr. 7/2026 — Proiect X",
    iesit: "ex: Raport nr. 3/2026 — Proiect X",
  },
  "proces-verbal": {
    intrat: "ex: PV receptie nr. 5/2026 — Proiect X",
    iesit: "ex: PV predare documentatie — Proiect X",
  },
  notificare: {
    intrat: "ex: Notificare finalizare lucrari — Proiect X",
    iesit: "ex: Notificare incepere lucrari — Proiect X",
  },
  comunicare: {
    intrat: "ex: Comunicare completari necesare — Proiect X",
    iesit: "ex: Comunicare nr. 18/2026 — Proiect X",
  },
  "apel-telefonic": {
    intrat: "ex: Apel primarie avize — Proiect X",
    iesit: "ex: Convorbire ISU programare — Proiect X",
  },
  videoconferinta: {
    intrat: "ex: Sedinta coordonare — Proiect X",
    iesit: "ex: Videoconferinta revizie PT — Proiect X",
  },
  altele: {
    intrat: "ex: PV receptie nr. 5/2026 — Proiect X",
    iesit: "ex: Documentatie PAC+DDE — Proiect X",
  },
};

const DEFAULT_PLACEHOLDER = "Tastati pentru sugestii...";

/**
 * Get a dynamic placeholder for the subject input based on document type
 * and direction.
 */
export function getSubjectPlaceholder(
  documentType: string,
  direction: RegistryDirection,
): string {
  const byType = SUBJECT_PLACEHOLDERS_MAP[documentType];
  if (!byType) return DEFAULT_PLACEHOLDER;
  return byType[direction] ?? DEFAULT_PLACEHOLDER;
}

// ── Public API ──

/**
 * Get seed templates for a given document type.
 */
export function getSeedTemplates(documentType: string): SubjectTemplate[] {
  return SEED_TEMPLATES[documentType] ?? SEED_TEMPLATES["altele"] ?? [];
}

/**
 * Get recommended templates for a document type: merge seeds + DB-learned.
 * DB-learned templates take priority (appear first), seeds fill in the rest.
 * De-duplicates by pattern.
 */
export function getRecommendedTemplates(
  documentType: string,
  dbTemplates: SubjectTemplate[],
): SubjectTemplate[] {
  const seeds = getSeedTemplates(documentType);
  const seen = new Set<string>();
  const result: SubjectTemplate[] = [];

  // DB-learned first (higher priority)
  for (const t of dbTemplates) {
    if (!seen.has(t.pattern)) {
      seen.add(t.pattern);
      result.push(t);
    }
  }

  // Then seeds (fill remaining slots)
  for (const t of seeds) {
    if (!seen.has(t.pattern)) {
      seen.add(t.pattern);
      result.push(t);
    }
  }

  return result.slice(0, 10);
}

/**
 * Extract reusable templates from an array of existing subjects.
 * Groups by pattern, counts frequency, returns sorted by frequency desc.
 */
export function extractTemplates(subjects: string[]): SubjectTemplate[] {
  if (subjects.length === 0) return [];

  // Deduplicate subjects
  const unique = Array.from(new Set(subjects));

  // Tokenize each subject and group by pattern
  const groups = new Map<
    string,
    { tokens: TemplateToken[]; example: string; count: number }
  >();

  for (const subj of unique) {
    // Skip very short subjects (no useful template)
    if (subj.length < 3) continue;

    const tokens = tokenize(subj);
    const fields = tokens.filter((t) => t.type === "field");

    // Only consider subjects that have at least one field (variable part)
    if (fields.length === 0) continue;

    const pattern = buildPattern(tokens);
    const existing = groups.get(pattern);
    if (existing) {
      existing.count++;
    } else {
      groups.set(pattern, { tokens, example: subj, count: 1 });
    }
  }

  // Count actual frequency: for each pattern, count how many of the
  // original (non-unique) subjects match
  // (Already counting unique matches above; for frequency boost, count
  //  duplicates from the full input array)
  const fullCounts = new Map<string, number>();
  for (const subj of subjects) {
    if (subj.length < 3) continue;
    const tokens = tokenize(subj);
    const fields = tokens.filter((t) => t.type === "field");
    if (fields.length === 0) continue;
    const pattern = buildPattern(tokens);
    fullCounts.set(pattern, (fullCounts.get(pattern) ?? 0) + 1);
  }

  // Build result array
  const result: SubjectTemplate[] = [];

  for (const [pattern, group] of groups) {
    const freq = fullCounts.get(pattern) ?? group.count;

    // Rebuild fields array from tokens (with sequential IDs)
    const fields: TemplateField[] = [];
    let fIdx = 0;
    const normalizedTokens: TemplateToken[] = group.tokens.map((t) => {
      if (t.type === "field" && t.field) {
        const field: TemplateField = { ...t.field, id: `f${fIdx}` };
        fields.push(field);
        fIdx++;
        return { ...t, field };
      }
      return t;
    });

    result.push({
      id: hashPattern(pattern),
      pattern,
      tokens: normalizedTokens,
      fields,
      frequency: freq,
      exampleSubject: group.example,
    });
  }

  // Sort by frequency desc, limit to 15
  result.sort((a, b) => b.frequency - a.frequency);
  return result.slice(0, 15);
}

/**
 * Assemble a final subject string from a template + field values.
 */
export function assembleSubject(
  template: SubjectTemplate,
  fieldValues: Record<string, string>,
): string {
  return template.tokens
    .map((t) => {
      if (t.type === "static") return t.value;
      return fieldValues[t.field!.id] ?? "";
    })
    .join("");
}

/**
 * Filter templates by a query string.
 * Matches against both the pattern and the example subject.
 */
export function filterTemplates(
  templates: SubjectTemplate[],
  query: string,
): SubjectTemplate[] {
  if (!query || query.length < 2) return [];
  const q = query.toLowerCase();
  return templates.filter(
    (t) =>
      t.pattern.toLowerCase().includes(q) ||
      t.exampleSubject.toLowerCase().includes(q),
  );
}

/** Recognized field placeholder names that can be used in dynamic templates */
const DYNAMIC_FIELD_NAMES = new Set(["nr", "an", "detalii", "proiect", "text"]);

/** Regex to detect at least one valid {fieldName} placeholder */
const HAS_PLACEHOLDER_RE = /\{(nr|an|detalii|proiect|text)\}/;

/**
 * Create a dynamic SubjectTemplate from free text containing `{fieldName}`
 * placeholders.  Recognised names: nr, an, detalii, proiect, text.
 *
 * Returns `null` when the text contains no valid placeholder.
 *
 * Example:
 *   createDynamicTemplate("Cerere CU — {proiect}")
 *   → SubjectTemplate with static "Cerere CU — " + field(proiect)
 */
export function createDynamicTemplate(
  pattern: string,
): SubjectTemplate | null {
  if (!HAS_PLACEHOLDER_RE.test(pattern)) return null;

  const tokens: TemplateToken[] = [];
  const fields: TemplateField[] = [];
  let fIdx = 0;

  // Split by {fieldName} placeholders (keeping the delimiters)
  const parts = pattern.split(/(\{[^}]+\})/);
  for (const part of parts) {
    if (!part) continue;
    const fieldMatch = part.match(/^\{(\w+)\}$/);
    if (fieldMatch) {
      const name = fieldMatch[1]!;
      if (!DYNAMIC_FIELD_NAMES.has(name)) {
        // Unknown placeholder — treat as static text
        tokens.push({ type: "static", value: part });
        continue;
      }
      const ft = resolveFieldType(name);
      const field: TemplateField = {
        id: `f${fIdx}`,
        name,
        placeholder: fieldPlaceholder(ft),
        width: fieldWidth(ft),
        fieldType: ft,
        defaultValue: ft === "an" ? CURRENT_YEAR : undefined,
      };
      fields.push(field);
      tokens.push({ type: "field", value: "", field });
      fIdx++;
    } else {
      tokens.push({ type: "static", value: part });
    }
  }

  if (fields.length === 0) return null;

  return {
    id: `dyn_${hashPattern(pattern)}`,
    pattern,
    tokens,
    fields,
    frequency: 0,
    exampleSubject: pattern,
    isSeed: true,
  };
}

/**
 * Filter existing subjects by query (plain text substring match).
 * Returns unique matches, limited to `limit`.
 */
export function filterSubjects(
  subjects: string[],
  query: string,
  limit = 5,
): string[] {
  if (!query || query.length < 2) return [];
  const q = query.toLowerCase();
  const seen = new Set<string>();
  const result: string[] = [];
  for (const s of subjects) {
    if (result.length >= limit) break;
    const lower = s.toLowerCase();
    if (lower.includes(q) && !seen.has(lower)) {
      seen.add(lower);
      result.push(s);
    }
  }
  return result;
}
