/**
 * Token Resolver — resolves unresolved SCSS token values using actual sass compilation.
 *
 * The regex-based resolver in token-parser.ts cannot handle SCSS module namespaces,
 * functions (color.scale, math.div), or map lookups. This module provides a fallback
 * that compiles the actual SCSS sources to extract computed CSS custom property values.
 *
 * Used at build time only — no runtime sass dependency in the MCP server.
 */

import { resolve, dirname, basename } from 'node:path';
import { existsSync, readdirSync } from 'node:fs';

/**
 * Round fractional RGB channel values produced by Sass color math.
 *
 * Sass functions like color.scale() and color.adjust() can produce
 * fractional values like rgb(217.8, 217.8, 217.8). This normalizes
 * them to clean integers: rgb(218, 218, 218).
 *
 * Alpha channels in rgba() are preserved as-is (they're legitimately fractional).
 */
function roundRgbValues(value: string): string {
  return value
    .replace(
      /rgb\(([^)]+)\)/g,
      (_full, inner: string) => {
        const parts = inner.split(',').map(p => p.trim());
        const rounded = parts.map(p => {
          const num = parseFloat(p);
          return isNaN(num) ? p : String(Math.round(num));
        });
        return `rgb(${rounded.join(', ')})`;
      },
    )
    .replace(
      /rgba\(([^)]+)\)/g,
      (_full, inner: string) => {
        const parts = inner.split(',').map(p => p.trim());
        // Round RGB channels (first 3), preserve alpha as-is
        const rounded = parts.map((p, i) => {
          if (i >= 3) return p; // alpha channel — don't round
          const num = parseFloat(p);
          return isNaN(num) ? p : String(Math.round(num));
        });
        return `rgba(${rounded.join(', ')})`;
      },
    );
}

/**
 * Resolve unresolved SCSS token values by compiling the project's token SCSS.
 *
 * Generates a temporary SCSS string that imports the project's _variables.scss
 * and includes the fui-css-variables mixin, then compiles it with sass to extract
 * the actual computed values for all CSS custom properties.
 *
 * @param unresolvedTokens - Tokens with values containing #{} or $ that need resolution
 * @param tokensDir - Absolute path to the directory containing _variables.scss
 * @returns Map of token name → resolved CSS value (only for tokens that were unresolved)
 */
export async function resolveTokensWithSass(
  unresolvedTokens: Array<{ name: string; value: string }>,
  tokensDir: string,
): Promise<Map<string, string>> {
  const resolvedMap = new Map<string, string>();

  // Filter to only tokens that actually need resolution
  const needsResolution = unresolvedTokens.filter(
    t => t.value.includes('#{') || t.value.includes('$'),
  );

  if (needsResolution.length === 0) {
    return resolvedMap;
  }

  try {
    // Dynamic import so sass is only loaded when needed (build-time only)
    const sass = await import('sass');

    // Find the _variables.scss file and determine the mixin name
    const variablesPath = findVariablesFile(tokensDir);
    if (!variablesPath) {
      return resolvedMap;
    }

    // Determine the module name for @use (filename without _ prefix and .scss suffix)
    const fileName = basename(variablesPath);
    const moduleName = fileName.replace(/^_/, '').replace(/\.scss$/, '');

    // Generate a SCSS string that imports the variables and includes the mixin
    const scssSource = `
@use '${moduleName}' as vars;
:root { @include vars.fui-css-variables; }
`;

    // Compile the SCSS with the tokens directory as a load path
    const compiled = sass.compileString(scssSource, {
      loadPaths: [tokensDir, dirname(tokensDir)],
      style: 'expanded',
      // Suppress sass deprecation warnings during build
      logger: { warn() {}, debug() {} } as never,
    });

    // Parse the compiled CSS for --fui-* custom property declarations
    const cssVarRegex = /(--[\w-]+)\s*:\s*([^;]+)/g;
    let match: RegExpExecArray | null;
    const allResolved = new Map<string, string>();

    while ((match = cssVarRegex.exec(compiled.css)) !== null) {
      allResolved.set(match[1], roundRgbValues(match[2].trim()));
    }

    // Only return values for the tokens that were originally unresolved
    for (const token of needsResolution) {
      const value = allResolved.get(token.name);
      if (value !== undefined) {
        resolvedMap.set(token.name, value);
      }
    }
  } catch {
    // Sass compilation failure is non-fatal — fall back to regex-resolved values
  }

  return resolvedMap;
}

/**
 * Find the _variables.scss file in the tokens directory.
 */
function findVariablesFile(tokensDir: string): string | null {
  const candidates = ['_variables.scss', 'variables.scss'];
  for (const name of candidates) {
    const path = resolve(tokensDir, name);
    if (existsSync(path)) {
      return path;
    }
  }

  // Fallback: look for any SCSS file containing 'css-variables' mixin
  try {
    const files = readdirSync(tokensDir).filter(f => f.endsWith('.scss'));
    for (const file of files) {
      const path = resolve(tokensDir, file);
      // We just need to find it exists; the @use import will handle the rest
      if (file.includes('variables') || file.includes('tokens')) {
        return path;
      }
    }
  } catch {
    // Directory read failure
  }

  return null;
}
