// src/lisp/primitives/string.ts
// String Primitives: concat, split, trim, upper, lower, substring, etc.

import type { IPrimitiveDefinition } from './mccarthy';

/**
 * CONCAT - Concatenate strings
 * (concat "Hello" " " "World") → "Hello World"
 */
export const concat: IPrimitiveDefinition = {
  name: 'concat',
  aliases: ['str'],
  handler: async (args, evaluate) => {
    const values = await Promise.all(args.map(a => evaluate(a)));
    return values.map(v => v === null || v === undefined ? '' : String(v)).join('');
  },
};

/**
 * SUBSTRING - Extract part of string
 * (substring "Hello" 0 2) → "He"
 */
export const substring: IPrimitiveDefinition = {
  name: 'substring',
  aliases: ['substr'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const start = await evaluate(args[1]) as number;
    const end = args.length > 2 ? await evaluate(args[2]) as number : undefined;
    return typeof s === 'string' ? s.substring(start, end) : '';
  },
};

/**
 * SPLIT - Split string into list
 * (split "a,b,c" ",") → ("a" "b" "c")
 */
export const split: IPrimitiveDefinition = {
  name: 'split',
  aliases: ['string-split'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const sep = args.length > 1 ? await evaluate(args[1]) as string : '';
    return typeof s === 'string' ? s.split(sep) : [];
  },
};

/**
 * JOIN - Join list into string
 * (join '("a" "b" "c") ",") → "a,b,c"
 */
export const join: IPrimitiveDefinition = {
  name: 'join',
  aliases: ['string-join'],
  handler: async (args, evaluate) => {
    const list = await evaluate(args[0]) as string[];
    const sep = args.length > 1 ? await evaluate(args[1]) as string : '';
    return Array.isArray(list) ? list.join(sep) : String(list);
  },
};

/**
 * UPPER - Convert to uppercase
 * (upper "hello") → "HELLO"
 */
export const upper: IPrimitiveDefinition = {
  name: 'upper',
  aliases: ['upcase', 'string-upcase'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    return typeof s === 'string' ? s.toUpperCase() : s;
  },
};

/**
 * LOWER - Convert to lowercase
 * (lower "HELLO") → "hello"
 */
export const lower: IPrimitiveDefinition = {
  name: 'lower',
  aliases: ['downcase', 'string-downcase'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    return typeof s === 'string' ? s.toLowerCase() : s;
  },
};

/**
 * TRIM - Remove whitespace from both ends
 * (trim "  hello  ") → "hello"
 */
export const trim: IPrimitiveDefinition = {
  name: 'trim',
  aliases: ['string-trim'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    return typeof s === 'string' ? s.trim() : s;
  },
};

/**
 * REPLACE - Replace occurrences
 * (replace "hello" "l" "w") → "hewwo"
 */
export const replace: IPrimitiveDefinition = {
  name: 'replace',
  aliases: ['string-replace'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const from = await evaluate(args[1]) as string;
    const to = await evaluate(args[2]) as string;
    return typeof s === 'string' ? s.split(from).join(to) : s;
  },
};

/**
 * STARTS-WITH - Check if string starts with prefix
 * (starts-with "hello" "he") → true
 */
export const startsWith: IPrimitiveDefinition = {
  name: 'starts-with',
  aliases: ['starts-with?', 'string-prefix?'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const prefix = await evaluate(args[1]) as string;
    return typeof s === 'string' && s.startsWith(prefix);
  },
};

/**
 * ENDS-WITH - Check if string ends with suffix
 * (ends-with "hello" "lo") → true
 */
export const endsWith: IPrimitiveDefinition = {
  name: 'ends-with',
  aliases: ['ends-with?', 'string-suffix?'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const suffix = await evaluate(args[1]) as string;
    return typeof s === 'string' && s.endsWith(suffix);
  },
};

/**
 * INCLUDES - Check if string contains substring
 * (includes "hello" "ell") → true
 */
export const includes: IPrimitiveDefinition = {
  name: 'includes',
  aliases: ['contains', 'string-contains?'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const sub = await evaluate(args[1]) as string;
    return typeof s === 'string' && s.includes(sub);
  },
};

/**
 * INDEX-OF - Find index of substring
 * (index-of "hello" "l") → 2
 */
export const indexOf: IPrimitiveDefinition = {
  name: 'index-of',
  aliases: ['string-index'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const sub = await evaluate(args[1]) as string;
    return typeof s === 'string' ? s.indexOf(sub) : -1;
  },
};

/**
 * CHAR-AT - Get character at index
 * (char-at "hello" 1) → "e"
 */
export const charAt: IPrimitiveDefinition = {
  name: 'char-at',
  aliases: ['string-ref'],
  handler: async (args, evaluate) => {
    const s = await evaluate(args[0]) as string;
    const i = await evaluate(args[1]) as number;
    return typeof s === 'string' ? s.charAt(i) : '';
  },
};

/**
 * STRING? - Is it a string?
 * (string? "hello") → true
 */
export const stringp: IPrimitiveDefinition = {
  name: 'string?',
  handler: async (args, evaluate) => {
    const val = await evaluate(args[0]);
    return typeof val === 'string';
  },
};

/**
 * FORMAT - Simple string formatting
 * (format "Hello {0}!" "World") → "Hello World!"
 */
export const format: IPrimitiveDefinition = {
  name: 'format',
  handler: async (args, evaluate) => {
    const template = await evaluate(args[0]) as string;
    const values = await Promise.all(args.slice(1).map(a => evaluate(a)));
    let result = String(template);
    values.forEach((v, i) => {
      result = result.replace(`{${i}}`, String(v));
    });
    return result;
  },
};

/**
 * All string primitives
 */
export const stringPrimitives: IPrimitiveDefinition[] = [
  concat,
  substring,
  split,
  join,
  upper,
  lower,
  trim,
  replace,
  startsWith,
  endsWith,
  includes,
  indexOf,
  charAt,
  stringp,
  format,
];
