import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { DATA_PATH } from './data-path';

type ToolInput = {
  type: string;
  description: string;
  values?: string;
  optional?: boolean;
};

export type ToolDefinition = {
  name: string;
  label: string;
  description: string;
  language: string;
  inputs: Record<string, ToolInput>;
  implementationPath: string;
  body: string;
};

type ToolMeta = {
  name: string;
  label: string;
  description: string;
  language: string;
  inputs: Record<string, ToolInput>;
};

function parseFrontmatter(content: string): { meta: Partial<ToolMeta>; body: string } {
  const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
  if (!match) return { meta: {}, body: content };

  const yamlBlock = match[1]!;
  const body = match[2]!;
  const meta: Record<string, unknown> = {};

  const lines = yamlBlock.split('\n');
  let currentKey: string | null = null;
  let currentObj: Record<string, unknown> | null = null;
  let currentSubKey: string | null = null;
  let currentSubObj: Record<string, unknown> | null = null;

  for (const line of lines) {
    const topMatch = line.match(/^(\w[\w-]*):\s*(.*)$/);
    if (topMatch && !line.startsWith('  ')) {
      if (currentSubObj && currentSubKey && currentObj) {
        currentObj[currentSubKey] = currentSubObj;
        currentSubObj = null;
        currentSubKey = null;
      }
      if (currentObj && currentKey) {
        meta[currentKey] = currentObj;
        currentObj = null;
        currentKey = null;
      }
      const [, key, value] = topMatch;
      if (!value || value.trim() === '') {
        currentKey = key!;
        currentObj = {};
      } else {
        meta[key!] = value.trim();
      }
      continue;
    }

    const midMatch = line.match(/^  (\w[\w-]*):\s*(.*)$/);
    if (midMatch && currentObj !== null) {
      if (currentSubObj && currentSubKey) {
        currentObj[currentSubKey] = currentSubObj;
        currentSubObj = null;
        currentSubKey = null;
      }
      const [, key, value] = midMatch;
      if (!value || value.trim() === '') {
        currentSubKey = key!;
        currentSubObj = {};
      } else {
        currentObj[key!] = value.trim();
      }
      continue;
    }

    const deepMatch = line.match(/^    (\w[\w-]*):\s*(.*)$/);
    if (deepMatch && currentSubObj !== null) {
      const [, key, value] = deepMatch;
      currentSubObj[key!] = value!.trim();
      continue;
    }

    const arrayMatch = line.match(/^    - (.+)$/);
    if (arrayMatch && currentSubObj !== null) {
      const key = Object.keys(currentSubObj).at(-1);
      if (key) {
        const arr = currentSubObj[key];
        if (Array.isArray(arr)) {
          arr.push(arrayMatch[1]!.trim());
        } else {
          currentSubObj[key] = [arrayMatch[1]!.trim()];
        }
      }
    }
  }

  if (currentSubObj && currentSubKey && currentObj) {
    currentObj[currentSubKey] = currentSubObj;
  }
  if (currentObj && currentKey) {
    meta[currentKey] = currentObj;
  }

  return { meta: meta as Partial<ToolMeta>, body };
}

function discoverToolsInDir(dir: string): ToolDefinition[] {
  if (!existsSync(dir)) return [];

  const tools: ToolDefinition[] = [];
  const entries = readdirSync(dir, { withFileTypes: true });

  for (const entry of entries) {
    if (!entry.isDirectory()) continue;

    const toolDir = join(dir, entry.name);
    const toolMdPath = join(toolDir, 'TOOL.md');
    if (!existsSync(toolMdPath)) continue;

    const indexTs = join(toolDir, 'index.ts');
    const indexJs = join(toolDir, 'index.js');
    const entryFile = existsSync(indexTs) ? indexTs : existsSync(indexJs) ? indexJs : null;
    if (!entryFile) continue;

    const content = readFileSync(toolMdPath, 'utf-8');
    const { meta, body } = parseFrontmatter(content);

    if (!meta.name || !meta.description) continue;

    tools.push({
      name: meta.name,
      label: meta.label ?? meta.name,
      description: meta.description,
      language: meta.language ?? 'typescript',
      inputs: (meta.inputs ?? {}) as Record<string, ToolInput>,
      implementationPath: entryFile,
      body,
    });
  }

  return tools;
}

export function discoverTools(email: string): ToolDefinition[] {
  const globalDir = join(DATA_PATH, 'tools');
  const userDir = join(DATA_PATH, email, 'tools');

  const globalTools = discoverToolsInDir(globalDir);
  const userTools = discoverToolsInDir(userDir);

  // User tools override global tools with the same name
  const seen = new Map<string, ToolDefinition>();
  for (const tool of globalTools) {
    seen.set(tool.name, tool);
  }
  for (const tool of userTools) {
    seen.set(tool.name, tool);
  }

  return Array.from(seen.values());
}
