// src/serialization/fromTopics.ts
// Parse topics representation back into IComponentSchema.

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

interface IMountSchema {
  mount: string;
  schema: IComponentSchema;
}

function mountDepth(mount: string): number {
  return mount.split('.').filter(Boolean).length;
}

function toPascalCase(source: string): string {
  return source
    .split(/[-_.\s]+/)
    .filter(Boolean)
    .map((token) => token.charAt(0).toUpperCase() + token.slice(1))
    .join('');
}

function deriveNameFromMount(mount: string): string {
  const leaf = mount.split('.').filter(Boolean).pop() || 'Component';
  return toPascalCase(leaf);
}

function createSchema(mount: string): IComponentSchema {
  return {
    name: deriveNameFromMount(mount),
    mount,
    accepts: {},
    emits: {},
    children: [],
    sourceFormat: 'topics',
  };
}

function parseTopicLine(line: string): { mount: string; kind: 'accepts' | 'emits'; name: string } | null {
  const acceptsMatch = line.match(/^(.+)\.accepts\.([^.]+)$/);
  if (acceptsMatch) {
    return { mount: acceptsMatch[1], kind: 'accepts', name: acceptsMatch[2] };
  }
  const emitsMatch = line.match(/^(.+)\.emits\.([^.]+)$/);
  if (emitsMatch) {
    return { mount: emitsMatch[1], kind: 'emits', name: emitsMatch[2] };
  }
  return null;
}

/**
 * Parse topics format produced by toTopics().
 */
export function fromTopics(source: string): IParseResult<IComponentSchema> {
  try {
    const map = new Map<string, IMountSchema>();
    const lines = source
      .split(/\r?\n/)
      .map((line) => line.trim())
      .filter((line) => line.length > 0 && !line.startsWith('#'));

    for (const line of lines) {
      const parsed = parseTopicLine(line);
      if (!parsed) continue;

      let entry = map.get(parsed.mount);
      if (!entry) {
        entry = { mount: parsed.mount, schema: createSchema(parsed.mount) };
        map.set(parsed.mount, entry);
      }

      if (parsed.kind === 'accepts') {
        entry.schema.accepts[parsed.name] = { params: {} };
      } else {
        entry.schema.emits[parsed.name] = { payload: {} };
      }
    }

    if (map.size === 0) {
      return { success: false, error: 'Topics parse error: no accepts/emits topics were found' };
    }

    const mounts = Array.from(map.keys()).sort((a, b) => mountDepth(a) - mountDepth(b));

    // Build a best-effort hierarchy from dot-mount ancestry.
    for (const mount of mounts) {
      const parentMount = mount.split('.').slice(0, -1).join('.');
      if (!parentMount || !map.has(parentMount)) continue;
      const parent = map.get(parentMount)!.schema;
      const child = map.get(mount)!.schema;
      parent.children = parent.children || [];
      if (!parent.children.some((entry) => entry.mount === child.mount)) {
        parent.children.push(child);
      }
    }

    // Find top-level nodes (no in-map parent).
    const roots = mounts
      .filter((mount) => {
        const parentMount = mount.split('.').slice(0, -1).join('.');
        return parentMount.length === 0 || !map.has(parentMount);
      })
      .map((mount) => map.get(mount)!.schema);

    if (roots.length === 1) {
      return { success: true, value: roots[0] };
    }

    return {
      success: true,
      value: {
        name: 'ComponentTree',
        mount: 'component-tree',
        accepts: {},
        emits: {},
        children: roots,
        sourceFormat: 'topics',
      },
    };
  } catch (err) {
    return {
      success: false,
      error: `Topics parse error: ${err instanceof Error ? err.message : String(err)}`,
    };
  }
}
