import type { RuleMetadata } from "./types";

export interface RuleFrontmatterResult {
  metadata: RuleMetadata;
  body: string;
}

/**
 * Parse YAML frontmatter from rule file content
 * Supports:
 * - Single string: globs: "**\/*.py"
 * - Inline array: globs: ["**\/*.py", "src/**\/*.ts"]
 * - Multi-line array:
 *   globs:
 *     - "**\/*.py"
 *     - "src/**\/*.ts"
 * - Comma-separated: globs: "**\/*.py, src/**\/*.ts"
 * - Claude Code 'paths' field (alias for globs)
 */
export function parseRuleFrontmatter(content: string): RuleFrontmatterResult {
  const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
  const match = content.match(frontmatterRegex);

  if (!match) {
    return { metadata: {}, body: content };
  }

  const yamlContent = match[1];
  const body = match[2];

  try {
    const metadata = parseYamlContent(yamlContent);
    return { metadata, body };
  } catch {
    return { metadata: {}, body: content };
  }
}

/**
 * Parse YAML content without external library
 */
function parseYamlContent(yamlContent: string): RuleMetadata {
  const lines = yamlContent.split("\n");
  const metadata: RuleMetadata = {};

  let i = 0;
  while (i < lines.length) {
    const line = lines[i];
    const colonIndex = line.indexOf(":");

    if (colonIndex === -1) {
      i++;
      continue;
    }

    const key = line.slice(0, colonIndex).trim();
    const rawValue = line.slice(colonIndex + 1).trim();

    if (key === "description") {
      metadata.description = parseStringValue(rawValue);
    } else if (key === "alwaysApply") {
      metadata.alwaysApply = rawValue === "true";
    } else if (key === "globs" || key === "paths") {
      const { value, consumed } = parseArrayOrStringValue(rawValue, lines, i);
      // Merge paths into globs (Claude Code compatibility)
      if (key === "paths") {
        metadata.globs = mergeGlobs(metadata.globs, value);
      } else {
        metadata.globs = mergeGlobs(metadata.globs, value);
      }
      i += consumed;
      continue;
    }

    i++;
  }

  return metadata;
}

/**
 * Parse a string value, removing surrounding quotes
 */
function parseStringValue(value: string): string {
  if (!value) return "";

  // Remove surrounding quotes
  if (
    (value.startsWith('"') && value.endsWith('"')) ||
    (value.startsWith("'") && value.endsWith("'"))
  ) {
    return value.slice(1, -1);
  }

  return value;
}

/**
 * Parse array or string value from YAML
 * Returns the parsed value and number of lines consumed
 */
function parseArrayOrStringValue(
  rawValue: string,
  lines: string[],
  currentIndex: number
): { value: string | string[]; consumed: number } {
  // Case 1: Inline array ["a", "b", "c"]
  if (rawValue.startsWith("[")) {
    return { value: parseInlineArray(rawValue), consumed: 1 };
  }

  // Case 2: Multi-line array (value is empty, next lines start with "  - ")
  if (!rawValue || rawValue === "") {
    const arrayItems: string[] = [];
    let consumed = 1;

    for (let j = currentIndex + 1; j < lines.length; j++) {
      const nextLine = lines[j];

      // Check if this is an array item (starts with whitespace + dash)
      const arrayMatch = nextLine.match(/^\s+-\s*(.*)$/);
      if (arrayMatch) {
        const itemValue = parseStringValue(arrayMatch[1].trim());
        if (itemValue) {
          arrayItems.push(itemValue);
        }
        consumed++;
      } else if (nextLine.trim() === "") {
        // Skip empty lines within array
        consumed++;
      } else {
        // Not an array item, stop
        break;
      }
    }

    if (arrayItems.length > 0) {
      return { value: arrayItems, consumed };
    }
  }

  // Case 3: Comma-separated patterns in single string
  const stringValue = parseStringValue(rawValue);
  if (stringValue.includes(",")) {
    const items = stringValue
      .split(",")
      .map((s) => s.trim())
      .filter((s) => s.length > 0);
    return { value: items, consumed: 1 };
  }

  // Case 4: Single string value
  return { value: stringValue, consumed: 1 };
}

/**
 * Parse inline JSON-like array: ["a", "b", "c"]
 */
function parseInlineArray(value: string): string[] {
  // Remove brackets
  const content = value.slice(1, value.lastIndexOf("]")).trim();
  if (!content) return [];

  const items: string[] = [];
  let current = "";
  let inQuote = false;
  let quoteChar = "";

  for (let i = 0; i < content.length; i++) {
    const char = content[i];

    if (!inQuote && (char === '"' || char === "'")) {
      inQuote = true;
      quoteChar = char;
    } else if (inQuote && char === quoteChar) {
      inQuote = false;
      quoteChar = "";
    } else if (!inQuote && char === ",") {
      const trimmed = current.trim();
      if (trimmed) {
        items.push(parseStringValue(trimmed));
      }
      current = "";
    } else {
      current += char;
    }
  }

  // Don't forget the last item
  const trimmed = current.trim();
  if (trimmed) {
    items.push(parseStringValue(trimmed));
  }

  return items;
}

/**
 * Merge two globs values (for combining paths and globs)
 */
function mergeGlobs(
  existing: string | string[] | undefined,
  newValue: string | string[]
): string | string[] {
  if (!existing) return newValue;

  const existingArray = Array.isArray(existing) ? existing : [existing];
  const newArray = Array.isArray(newValue) ? newValue : [newValue];

  return [...existingArray, ...newArray];
}
