// src/serialization/fromFluent.ts
// Parse Fluent DSL representation back into IComponentSchema.

import type { IComponentSchema } from './IComponentSchema';
import type { IParamSchema } from './IParamSchema';
import type { IParseResult } from './IParseResult';

const PARAM_TYPES: ReadonlySet<IParamSchema['type']> = new Set([
  'string',
  'number',
  'boolean',
  'object',
  'array',
  'any',
]);

function normalizeParamType(typeToken: string): IParamSchema['type'] {
  return PARAM_TYPES.has(typeToken as IParamSchema['type'])
    ? (typeToken as IParamSchema['type'])
    : 'any';
}

function parseParamsObject(raw: string | undefined): Record<string, IParamSchema> {
  if (!raw) return {};
  const trimmed = raw.trim();
  if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) return {};

  const body = trimmed.slice(1, -1);
  const result: Record<string, IParamSchema> = {};
  const entryRegex = /([A-Za-z_$][\w$]*)\s*:\s*'([^']+)'/g;
  let match: RegExpExecArray | null;
  while ((match = entryRegex.exec(body)) !== null) {
    const name = match[1];
    const typeToken = match[2];
    const optional = typeToken.endsWith('?');
    const normalizedType = normalizeParamType(optional ? typeToken.slice(0, -1) : typeToken);
    result[name] = {
      type: normalizedType,
      optional,
    };
  }
  return result;
}

function findBalancedSegment(source: string, startIndex: number): { value: string; nextIndex: number } | null {
  if (source[startIndex] !== '(') return null;
  let depth = 0;
  let inString = false;
  let quote = '';
  for (let i = startIndex; i < source.length; i++) {
    const ch = source[i];
    const prev = i > 0 ? source[i - 1] : '';

    if ((ch === '"' || ch === "'") && prev !== '\\') {
      if (!inString) {
        inString = true;
        quote = ch;
      } else if (quote === ch) {
        inString = false;
      }
    }

    if (inString) continue;

    if (ch === '(') depth++;
    if (ch === ')') depth--;

    if (depth === 0) {
      return { value: source.slice(startIndex + 1, i), nextIndex: i + 1 };
    }
  }
  return null;
}

function parseChildren(source: string): IComponentSchema[] {
  const children: IComponentSchema[] = [];
  let cursor = 0;
  const marker = '.child(';

  while (cursor < source.length) {
    const idx = source.indexOf(marker, cursor);
    if (idx === -1) break;
    const parenStart = idx + marker.length - 1; // points to '('
    const segment = findBalancedSegment(source, parenStart);
    if (!segment) break;

    const childExpr = segment.value.trim();
    const childParsed = fromFluent(childExpr);
    if (childParsed.success && childParsed.value) {
      children.push(childParsed.value);
    }
    cursor = segment.nextIndex;
  }

  return children;
}

/**
 * Parse Fluent DSL produced by toFluent().
 */
export function fromFluent(source: string): IParseResult<IComponentSchema> {
  try {
    const normalized = source.trim();
    if (!normalized.startsWith('component(')) {
      return { success: false, error: 'Fluent parse error: expected component(...) root expression' };
    }

    const headerMatch = normalized.match(
      /component\(\s*'([^']+)'\s*(?:,\s*\{\s*mount:\s*'([^']+)'\s*\}\s*)?\)/
    );
    if (!headerMatch) {
      return { success: false, error: 'Fluent parse error: unable to parse component header' };
    }

    const name = headerMatch[1];
    const mount = headerMatch[2];

    const accepts: IComponentSchema['accepts'] = {};
    const emits: IComponentSchema['emits'] = {};

    const acceptsRegex = /\.accepts\(\s*'([^']+)'\s*(?:,\s*(\{[^)]*\}))?\s*\)/g;
    let acceptsMatch: RegExpExecArray | null;
    while ((acceptsMatch = acceptsRegex.exec(normalized)) !== null) {
      const op = acceptsMatch[1];
      accepts[op] = { params: parseParamsObject(acceptsMatch[2]) };
    }

    const emitsRegex = /\.emits\(\s*'([^']+)'\s*(?:,\s*(\{[^)]*\}))?\s*\)/g;
    let emitsMatch: RegExpExecArray | null;
    while ((emitsMatch = emitsRegex.exec(normalized)) !== null) {
      const ev = emitsMatch[1];
      emits[ev] = { payload: parseParamsObject(emitsMatch[2]) };
    }

    const children = parseChildren(normalized);

    const value: IComponentSchema = {
      name,
      mount,
      accepts,
      emits,
      ...(children.length > 0 ? { children } : {}),
      sourceFormat: 'fluent',
    };
    return { success: true, value };
  } catch (err) {
    return {
      success: false,
      error: `Fluent parse error: ${err instanceof Error ? err.message : String(err)}`,
    };
  }
}
