/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

const fs = require('fs');
const path = require('path');

const stylesDir = path.resolve(__dirname, 'node_modules/highlight.js/styles'); // Path to Highlight.js styles directory
const jsOutputFile = path.resolve(__dirname, 'themeStyles.js'); // Path to output JavaScript file
const goOutputFile = path.resolve(__dirname, 'theme_list.go'); // Path to output Go file
const colorInfoOutputFile = path.resolve(__dirname, 'themeColors.js'); // Path to output color information file

// Read all CSS files from the styles directory
let themes = fs.readdirSync(stylesDir).filter(file => file.endsWith('.css'));

// Prioritize .min.css files
const minifiedFiles = new Set(themes.filter(file => file.endsWith('.min.css')).map(file => file.replace('.min.css', '')));
themes = themes.filter(file => {
  const baseName = file.replace('.css', '').replace('.min', '');
  // Skip unminified versions if corresponding .min.css file exists
  return !minifiedFiles.has(baseName) || file.endsWith('.min.css');
});

// Group themes and classify by naming conventions
const themeMap = {};
let themeList = [];
const themeColors = [];
let defaultDarkTheme = null;
let defaultLightTheme = null;

const cssColorNames = {
  black: '#000000',
  white: '#ffffff',
  navy: '#000080',
  // Add more color names as needed if the background color in css is not defined in a standard method
};

// Convert color names (e.g., 'black', 'white') to hex values
function convertColorNameToHex(colorName) {
  return cssColorNames[colorName.toLowerCase()] || null;
}

// Normalize hex color code (e.g., convert shorthand hex to full length)
function normalizeHexColor(hexColor) {
  hexColor = hexColor.startsWith('#') ? hexColor.slice(1) : hexColor;
  if (hexColor.length === 3) {
    hexColor = hexColor.split('').map(char => char + char).join('');
  }
  return hexColor;
}

// Determine if a theme is dark based on its background color
function isDarkTheme(color) {
  if (!color.startsWith('#') && !color.startsWith('rgb')) {
    const hexColor = convertColorNameToHex(color);
    if (hexColor) {
      color = hexColor;
    } else {
      return false;
    }
  }
  const hexColor = normalizeHexColor(color);
  const rgb = parseInt(hexColor, 16);
  const r = (rgb >> 16) & 0xff;
  const g = (rgb >> 8) & 0xff;
  const b = (rgb >> 0) & 0xff;
  const brightness = (r * 299 + g * 587 + b * 114) / 1000; // Calculate brightness based on RGB values
  return brightness < 128; // Dark theme if brightness is below the threshold
}

// Process each theme file
themes.forEach(file => {
  const themeName = file.replace('.css', '').replace('.min', '');
  const [base, ...variantParts] = themeName.split('-');
  const variant = variantParts.join('-');

  if (!themeMap[base]) {
    themeMap[base] = {};
  }

  let isDark = false;
  let backgroundColor = null;

  // Identify light or dark themes based on the variant name
  if (variant.includes('light')) {
    if (!themeMap[base].light || themeMap[base].light.length > file.length) {
      themeMap[base].light = `() => import('highlight.js/styles/${file}?inline')`;
      if (!defaultLightTheme) {
        defaultLightTheme = themeMap[base].light;
      }
    }
  } else if (variant.includes('dark')) {
    if (!themeMap[base].dark || themeMap[base].dark.length > file.length) {
      themeMap[base].dark = `() => import('highlight.js/styles/${file}?inline')`;
      if (!defaultDarkTheme) {
        defaultDarkTheme = themeMap[base].dark;
      }
    }
  } else {
    // Extract background color from CSS content and determine if it's a dark theme
    const cssContent = fs.readFileSync(path.resolve(stylesDir, file), 'utf-8');
    const backgroundMatch = cssContent.match(/\.hljs\s*{[^}]*?\s*background(?:-color)?:\s*(#[0-9a-fA-F]{3,6}|rgb\([^)]+\)|[a-zA-Z]+|url\([^)]+\))/i);
    backgroundColor = backgroundMatch ? backgroundMatch[1].trim() : null;

    if (backgroundColor) {
      if (backgroundColor.startsWith('url')) {
        backgroundColor = null;
      } else if (backgroundColor.startsWith('#')) {
        isDark = isDarkTheme(backgroundColor);
      } else if (backgroundColor.startsWith('rgb')) {
        const rgbValues = backgroundColor.match(/\d+/g).map(Number);
        const brightness = (rgbValues[0] * 299 + rgbValues[1] * 587 + rgbValues[2] * 114) / 1000;
        isDark = brightness < 128;
      } else {
        isDark = isDarkTheme(backgroundColor);
      }
    }

    // Assign the theme to light or dark based on the background color
    if (isDark) {
      if (!themeMap[base].dark || themeMap[base].dark.length > file.length) {
        themeMap[base].dark = `() => import('highlight.js/styles/${file}?inline')`;
        if (!defaultDarkTheme) {
          defaultDarkTheme = themeMap[base].dark;
        }
      }
    } else {
      if (!themeMap[base].light || themeMap[base].light.length > file.length) {
        themeMap[base].light = `() => import('highlight.js/styles/${file}?inline')`;
        if (!defaultLightTheme) {
          defaultLightTheme = themeMap[base].light;
        }
      }
    }
  }

  // Add theme to the theme list
  if (!themeList.includes(base)) {
    themeList.push(base);
  }

  // Store theme color information
  if (backgroundColor) {
    themeColors.push({
      theme: base,
      variant: isDark ? 'dark' : 'light',
      color: backgroundColor
    });
  }
});

// Classify themes based on the presence of light and dark variants
themeList = themeList.map(base => {
  if (themeMap[base].light && !themeMap[base].dark) {
    return `${base}-light`;
  } else if (!themeMap[base].light && themeMap[base].dark) {
    return `${base}-dark`;
  } else if (themeMap[base].light && themeMap[base].dark) {
    return `${base}-all`;
  } else {
    return base;
  }
});

// Assign default light and dark themes if missing
Object.keys(themeMap).forEach(base => {
  if (!themeMap[base].dark && defaultDarkTheme) {
    themeMap[base].dark = defaultDarkTheme;
  }
  if (!themeMap[base].light && defaultLightTheme) {
    themeMap[base].light = defaultLightTheme;
  }
});

// Generate the JavaScript output for theme styles
const jsOutput = `export const themeStyles = {\n${Object.entries(themeMap)
  .map(([theme, variants]) => 
    `  ${JSON.stringify(theme)}: {\n    light: ${variants.light},\n    dark: ${variants.dark}\n  }`
  ).join(',\n')}\n};`;

fs.writeFileSync(jsOutputFile, jsOutput); // Write the theme styles to JavaScript file

// Generate the Go output for theme list
const goOutput = `
package render_markdown_codehighlight

var ThemeList = []string{
${themeList.map(theme => `"${theme}"`).join(",\n  ")},
}
`;

fs.writeFileSync(goOutputFile, goOutput); // Write the theme list to Go file

console.log('Theme styles, Go theme list, and color information generated successfully!');
