/**
 * src/session/locale.ts — guarantee the spawned PTY has a UTF-8 locale.
 *
 * The bug this fixes: when the server is launched from Finder / launchd (the Mac
 * desktop app, or the launchd-managed tunnel agent) the process environment has
 * NO `LANG` / `LC_*` at all — unlike a shell started from Terminal.app. tmux
 * decides per client whether the terminal is UTF-8 capable purely from those
 * variables, so with none set it falls back to its non-UTF-8 mode and:
 *
 *   - rewrites every wide character to `_`  →  `中文测试` renders as `________`
 *   - rewrites other non-Latin-1 glyphs to `_` (`✓`, `⏺`, emoji …)
 *   - downgrades double-line box drawing (`═║╔╗`) to DEC Special Graphics
 *     (`ESC ( 0` + `qxlk`), i.e. single lines
 *
 * That mangling happens on the server side, *before* the bytes reach xterm.js,
 * so no amount of frontend font work can recover it. The `-l` login shell can't
 * fix it either: tmux is the PTY's root process and has already made its
 * decision by the time the shell sources `~/.zprofile`.
 *
 * Policy: leave the environment alone whenever the effective charset is already
 * UTF-8 — a user who picked `zh_CN.UTF-8` or `ja_JP.UTF-8` keeps it. Only a
 * missing or non-UTF-8 charset is replaced. Precedence follows POSIX:
 * `LC_ALL` > `LC_CTYPE` > `LANG`.
 */

/** Fallback locale when the environment specifies no UTF-8 charset. */
export const DEFAULT_UTF8_LOCALE = 'en_US.UTF-8';

/** Matches the charset suffix of a locale: `.UTF-8`, `.utf8`, or a bare `UTF-8`. */
const UTF8_PATTERN = /utf-?8$/i;

/** Environment mapping as node-pty / process.env exposes it. */
type Env = Readonly<Record<string, string | undefined>>;

function isUtf8(value: string | undefined): boolean {
  return value !== undefined && value !== '' && UTF8_PATTERN.test(value);
}

/**
 * Return a copy of `env` that is guaranteed to select a UTF-8 charset.
 *
 * Existing values are never rewritten — if the effective locale is already
 * UTF-8 the env comes back unchanged (aside from being a fresh object).
 */
export function withUtf8Locale(env: Env): Record<string, string | undefined> {
  // LC_ALL outranks everything; LC_CTYPE outranks LANG for character handling.
  // If whichever one is in effect is already UTF-8, there is nothing to do.
  const effective =
    env.LC_ALL !== undefined && env.LC_ALL !== ''
      ? env.LC_ALL
      : env.LC_CTYPE !== undefined && env.LC_CTYPE !== ''
        ? env.LC_CTYPE
        : env.LANG;

  if (isUtf8(effective)) return { ...env };

  // Setting LANG (the lowest-precedence variable) is the least invasive fix, but
  // it only takes effect if nothing above it is overriding — so clear a
  // non-UTF-8 LC_ALL / LC_CTYPE that would otherwise win.
  const next: Record<string, string | undefined> = { ...env, LANG: DEFAULT_UTF8_LOCALE };
  if (env.LC_ALL !== undefined && env.LC_ALL !== '') delete next.LC_ALL;
  if (env.LC_CTYPE !== undefined && env.LC_CTYPE !== '') delete next.LC_CTYPE;
  return next;
}
