import db from '../db.js';
import { uriToClashLine } from '../parsers/toClash.js';

export function generateClashConfig(): string {
  const sub = db.prepare(
    'SELECT raw_config_clash FROM subscriptions WHERE enabled = 1 AND raw_config_clash IS NOT NULL ORDER BY id LIMIT 1'
  ).get() as any;

  if (!sub?.raw_config_clash) {
    return '# No Clash config available. Add a subscription with a Clash URL and fetch it.';
  }

  const staticNodes = db.prepare(
    'SELECT uri, name FROM static_nodes WHERE enabled = 1 ORDER BY sort_order, id'
  ).all() as any[];

  if (staticNodes.length === 0) {
    return sub.raw_config_clash;
  }

  const clashLines = staticNodes
    .map((n: any) => uriToClashLine(n.uri))
    .filter((l): l is string => l !== null);

  const staticNames = staticNodes.map((n: any) => n.name as string);

  if (clashLines.length === 0) {
    return sub.raw_config_clash;
  }

  let config = injectProxies(sub.raw_config_clash, clashLines);
  config = injectProxyGroupNames(config, staticNames);
  return config;
}

/**
 * Inject static node YAML lines into the proxies: section.
 * Inserts immediately after the `proxies:` key line.
 * If no `proxies:` key exists, inserts a new proxies block before `proxy-groups:`.
 */
function injectProxies(config: string, clashLines: string[]): string {
  const lines = config.split('\n');
  const result: string[] = [];
  let injected = false;

  for (let i = 0; i < lines.length; i++) {
    const trimmed = lines[i].trim();

    if (!injected && trimmed === 'proxies:') {
      result.push(lines[i]);
      // Inject right after the `proxies:` key
      for (const cl of clashLines) result.push(cl);
      injected = true;
      continue;
    }

    // If proxies: never appeared, inject before proxy-groups:
    if (!injected && trimmed === 'proxy-groups:') {
      result.push('proxies:');
      for (const cl of clashLines) result.push(cl);
      result.push('');
      injected = true;
    }

    result.push(lines[i]);
  }

  // Fallback: append at end if neither key was found
  if (!injected) {
    result.push('');
    result.push('proxies:');
    for (const cl of clashLines) result.push(cl);
  }

  return result.join('\n');
}

/**
 * Inject static node names into every `type: select` proxy-group's proxies sub-list.
 * Handles both block sequence (`      - name`) and inline array (`proxies: [a, b]`) formats.
 */
function injectProxyGroupNames(config: string, names: string[]): string {
  const lines = config.split('\n');
  const result: string[] = [];

  let inProxyGroups = false;
  let inSelectGroup = false;
  let inProxiesSublist = false;

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    const trimmed = line.trim();

    // Detect top-level section changes
    if (/^[a-zA-Z]/.test(line) && line.includes(':')) {
      const key = line.split(':')[0].trim();
      if (key === 'proxy-groups') {
        inProxyGroups = true;
        inSelectGroup = false;
        inProxiesSublist = false;
      } else if (!line.startsWith(' ') && !line.startsWith('-')) {
        inProxyGroups = false;
        inSelectGroup = false;
        inProxiesSublist = false;
      }
    }

    if (!inProxyGroups) {
      result.push(line);
      continue;
    }

    // New group entry: reset state
    if (/^\s*-\s+name:/.test(line)) {
      inSelectGroup = false;
      inProxiesSublist = false;
      result.push(line);
      continue;
    }

    // Detect `type: select` within a group
    if (trimmed === 'type: select') {
      inSelectGroup = true;
      result.push(line);
      continue;
    }

    if (inSelectGroup) {
      // Handle inline array: proxies: [node1, node2, ...]
      if (/^\s+proxies:\s*\[/.test(line)) {
        // Append names before the closing ]
        const closeBracket = line.lastIndexOf(']');
        if (closeBracket !== -1) {
          const before = line.slice(0, closeBracket);
          const after = line.slice(closeBracket);
          result.push(before + ', ' + names.join(', ') + after);
        } else {
          result.push(line);
        }
        continue;
      }

      // Handle block sequence: `    proxies:` followed by `      - name` items
      if (/^\s+proxies:\s*$/.test(line)) {
        inProxiesSublist = true;
        result.push(line);
        continue;
      }

      if (inProxiesSublist) {
        // Check if next line is still a proxies list item
        const nextLine = lines[i + 1];
        const isLastItem = !nextLine || !/^\s{4,}-\s/.test(nextLine);

        result.push(line);

        if (isLastItem && /^\s{4,}-\s/.test(line)) {
          // Inject names after last item
          const indent = line.match(/^(\s+)/)?.[1] || '      ';
          for (const name of names) result.push(`${indent}- ${name}`);
          inProxiesSublist = false;
        }
        continue;
      }
    }

    result.push(line);
  }

  return result.join('\n');
}
