import fs from "fs";
import path from "path";
import { optimize } from "svgo";
import { fileURLToPath } from "url";
import { dirname } from "path";
import outlineConfig from "./svgo.24.outline.js";
import solidConfig from "./svgo.24.solid.js";
import deprecatedIcons from "./deprecated.json" assert { type: "json" };

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const iconMetadataPath = path.resolve(__dirname, "./iconMetadata.json");
const iconMetadata = JSON.parse(fs.readFileSync(iconMetadataPath, "utf-8"));

const mapSvgAttributes = (svgContent) => {
  return svgContent
    .replace(/fill-rule/g, "fillRule")
    .replace(/clip-rule/g, "clipRule");
};

const generateIconComponent = (
  name,
  svgContent,
  description = "",
  usage = [],
  isDeprecated = false,
  aliases = []
) => {
  return `
import * as React from 'react';

interface IconProps extends React.SVGAttributes<SVGElement> {
  children?: never;
  color?: string;
}

/**
 * @name ${name}Icon
 ${
   aliases.length
     ? `* @alias ${aliases.map((alias) => alias + "Icon").join(", ")}`
     : ""
 }
 *
 * @category ${usage.length ? "solid" : "outline"}
 *
 * @description
 * ${description}
 *
 * ${isDeprecated ? "@deprecated\n * " : ""}
 * @usage
 * ${usage.map((item) => `- ${item}`).join("\n * ")}
 *
 * @accessibility
 * Asegurarse de incluir un atributo \`aria-label\` o \`aria-hidden="true"\` si el ícono es decorativo.
 *
 * @returns {JSX.Element} Componente SVG.
 */
const ${name}Icon = React.forwardRef<SVGSVGElement, IconProps>(
  ({ color = 'currentColor', ...props }, forwardedRef) => {
    return (
      ${mapSvgAttributes(svgContent).replace(
        "<svg",
        "<svg {...props} ref={forwardedRef}"
      )}
    );
  }
);

${name}Icon.displayName = '${name}Icon';

export { ${name}Icon };
`;
};

const generateIndexFile = (components, iconType) => {
  const exports = components
    .map(
      ({ name, aliases }) =>
        `export { ${name}Icon${
          aliases.length
            ? `, ${aliases
                .map((alias) => `${name}Icon as ${alias}Icon`)
                .join(", ")}`
            : ""
        } } from './${name}Icon';`
    )
    .join("\n");
  const indexPath = path.resolve(__dirname, `../src/${iconType}/index.ts`);
  fs.writeFileSync(indexPath, exports, "utf-8");
};

const processIcons = async (iconType) => {
  const svgDir = path.resolve(__dirname, `../src/svgs/${iconType}`);
  const componentDir = path.resolve(__dirname, `../src/${iconType}`);

  if (!fs.existsSync(componentDir)) {
    fs.mkdirSync(componentDir, { recursive: true });
  }

  const components = [];
  const files = fs.readdirSync(svgDir);

  for (const file of files) {
    const filePath = path.resolve(svgDir, file);
    const svgContent = fs.readFileSync(filePath, "utf-8");

    const svgoConfig = iconType === "outline" ? outlineConfig : solidConfig;
    const { data } = await optimize(svgContent, svgoConfig);

    const componentName = file
      .replace(".svg", "")
      .replace(/(^\w|-\w)/g, clearAndUpper);
    const metadata = iconMetadata[componentName];
    const isDeprecated = deprecatedIcons.includes(componentName);

    if (!metadata) {
      console.warn(
        `Metadata for ${componentName} not found, generating without metadata.`
      );
    }

    const aliases = metadata && metadata.aliases ? metadata.aliases : [];

    components.push({ name: componentName, aliases });
    const componentContent = generateIconComponent(
      componentName,
      data,
      metadata ? metadata.description : "",
      metadata ? metadata.usage : [],
      isDeprecated,
      aliases
    );

    const componentPath = path.resolve(
      componentDir,
      `${componentName}Icon.tsx`
    );
    fs.writeFileSync(componentPath, componentContent, "utf-8");
  }

  generateIndexFile(components, iconType);
};

const clearAndUpper = (text) => text.replace(/-/, "").toUpperCase();

(async () => {
  await processIcons("solid");
  await processIcons("outline");
})();
