/**
 * CSS Conversion Utilities
 *
 * Provides functions for converting between CSS string and object formats,
 * with special handling for data URIs containing colons and semicolons, and SVG
 * generation for disclosure triangle list styles.
 */

import { isCustomListStyleImage } from "./templateResourceConstants";

/**
 * Generates a base64-encoded SVG data URI for a right-pointing disclosure triangle.
 */
export const generateDisclosureTriangleSVG = (): string => {
  // Right-pointing triangle SVG (16x16px)
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
  <polygon points="6,4 12,8 6,12" fill="currentColor"/>
</svg>`;

  const base64 = btoa(svg);
  return `url('data:image/svg+xml;base64,${base64}')`;
};

/**
 * Parses CSS declarations from a CSS string, correctly handling data URIs
 * with colons and semicolons inside url() values.
 */
export const parseCSSDeclarations = (
  cssString: string,
): Array<[string, string]> => {
  const results: Array<[string, string]> = [];
  let depth = 0;
  let current = "";

  for (let i = 0; i < cssString.length; i++) {
    const ch = cssString[i];
    if (ch === '(') depth++;
    else if (ch === ')') depth--;
    if (ch === ';' && depth === 0) {
      const decl = current.trim();
      if (decl) {
        const colonIdx = decl.indexOf(':');
        if (colonIdx > 0) {
          const prop = decl.slice(0, colonIdx).trim();
          const val = decl.slice(colonIdx + 1).trim();
          if (prop && val) results.push([prop, val]);
        }
      }
      current = '';
    } else {
      current += ch;
    }
  }
  // Handle last declaration if no trailing semicolon
  const lastDecl = current.trim();
  if (lastDecl) {
    const colonIdx = lastDecl.indexOf(':');
    if (colonIdx > 0) {
      const prop = lastDecl.slice(0, colonIdx).trim();
      const val = lastDecl.slice(colonIdx + 1).trim();
      if (prop && val) results.push([prop, val]);
    }
  }
  return results;
};

/**
 * Normalizes list-style properties to handle special values like disclosure-closed.
 */
export const normalizeListStyleProps = (
  obj: Record<string, string>,
): Record<string, string> => {
  const normalized = { ...obj };
  const specialListStyles = ["disclosure-closed", "disclosure-open", "none"];

  if (normalized["list-style"]) {
    const listStyleValue = normalized["list-style"].split(" ")[0];
    if (specialListStyles.includes(listStyleValue)) {
      delete normalized["list-style-type"];
      return normalized;
    }
    if (!normalized["list-style-type"]) {
      normalized["list-style-type"] = listStyleValue;
    }
  }

  if (normalized["list-style-type"] && !normalized["list-style"]) {
    normalized["list-style"] = normalized["list-style-type"];
  }

  return normalized;
};

/**
 * Converts a CSS string to a CSS object, correctly parsing data URIs
 * and adding SVG data URI for disclosure-closed.
 */
export const cssStringToObject = (cssString: string): Record<string, string> => {
  const obj: Record<string, string> = {};
  parseCSSDeclarations(cssString).forEach(([prop, val]) => {
    obj[prop] = val;
  });
  const normalized = normalizeListStyleProps(obj);
  if (normalized["list-style"] === "disclosure-closed") {
    normalized["list-style-image"] = generateDisclosureTriangleSVG();
  } else if (isCustomListStyleImage(normalized["list-style-image"])) {
    normalized["list-style"] = normalized["list-style"] || "none";
    delete normalized["list-style-type"];
  }
  return normalized;
};

/**
 * Converts a CSS object to a CSS string, formatting as "key: value;" pairs.
 */
export const cssObjectToString = (cssObject: Record<string, string>): string => {
  return Object.entries(cssObject)
    .filter(([_, value]) => value !== null && value !== undefined)
    .map(([key, value]) => `${key}: ${value};`)
    .join(' ');
};

export function omitCssProperties(
  cssString: string,
  properties: string[],
): string {
  const omitted = new Set(properties);
  const styles: Record<string, string> = {};
  parseCSSDeclarations(cssString).forEach(([prop, val]) => {
    if (!omitted.has(prop)) {
      styles[prop] = val;
    }
  });
  return cssObjectToString(styles);
}

export function mergeCssProperties(
  cssString: string,
  properties: Record<string, string | undefined>,
): string {
  const styles: Record<string, string> = {};
  parseCSSDeclarations(cssString).forEach(([prop, val]) => {
    styles[prop] = val;
  });
  Object.entries(properties).forEach(([key, value]) => {
    if (value === undefined || value === "") {
      delete styles[key];
    } else {
      styles[key] = value;
    }
  });
  return cssObjectToString(styles);
}