/**
 * UI label loader utility
 *
 * Loads user-facing display strings from language-specific YAML files
 * (labels_en.yaml / labels_ja.yaml) and provides
 * key-based access with template variable substitution.
 *
 * This module handles UI labels only — AI prompts live in ../prompts/.
 */

import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { parse as parseYaml } from 'yaml';
import type { Language } from '../../core/models/types.js';
import { DEFAULT_LANGUAGE } from '../constants.js';

/** Cached YAML data per language */
const labelCache = new Map<Language, Record<string, unknown>>();

function loadLabels(lang: Language): Record<string, unknown> {
  const cached = labelCache.get(lang);
  if (cached) return cached;
  const __dirname = dirname(fileURLToPath(import.meta.url));
  const yamlPath = join(__dirname, `labels_${lang}.yaml`);
  const content = readFileSync(yamlPath, 'utf-8');
  const data = parseYaml(content) as Record<string, unknown>;
  labelCache.set(lang, data);
  return data;
}

/**
 * Resolve a dot-separated key path to a value in a nested object.
 * Returns undefined if the path does not exist.
 */
function resolveKey(obj: Record<string, unknown>, keyPath: string): unknown {
  const parts = keyPath.split('.');
  let current: unknown = obj;
  for (const part of parts) {
    if (current === null || current === undefined || typeof current !== 'object') {
      return undefined;
    }
    current = (current as Record<string, unknown>)[part];
  }
  return current;
}

/**
 * Replace {key} placeholders in a template string with values from vars.
 * Unmatched placeholders are left as-is.
 */
function applyVars(template: string, vars: Record<string, string>): string {
  return template.replace(/\{(\w+)\}/g, (match, key: string) => {
    if (key in vars) {
      const value: string = vars[key] as string;
      return value;
    }
    return match;
  });
}

/**
 * Get a UI label string from the language-specific YAML by dot-separated key.
 *
 * When `lang` is provided, loads the corresponding language file.
 * When `lang` is omitted, uses DEFAULT_LANGUAGE.
 *
 * Template variables in `{name}` format are replaced when `vars` is given.
 */
export function getLabel(
  key: string,
  lang?: Language,
  vars?: Record<string, string>,
): string {
  const effectiveLang = lang ?? DEFAULT_LANGUAGE;
  const data = loadLabels(effectiveLang);

  const value = resolveKey(data, key);
  if (typeof value !== 'string') {
    throw new Error(`Label key not found: ${key}${lang ? ` (lang: ${lang})` : ''}`);
  }

  if (vars) {
    return applyVars(value, vars);
  }
  return value;
}

/**
 * Get a nested object from the language-specific YAML by dot-separated key.
 *
 * When `lang` is provided, loads the corresponding language file.
 * When `lang` is omitted, uses DEFAULT_LANGUAGE.
 *
 * Useful for structured label groups (e.g. UI text objects).
 */
export function getLabelObject<T>(key: string, lang?: Language): T {
  const effectiveLang = lang ?? DEFAULT_LANGUAGE;
  const data = loadLabels(effectiveLang);

  const value = resolveKey(data, key);
  if (value === undefined || value === null) {
    throw new Error(`Label key not found: ${key}${lang ? ` (lang: ${lang})` : ''}`);
  }

  return value as T;
}

/** Reset cached data (for testing) */
export function _resetLabelCache(): void {
  labelCache.clear();
}
