import { isPercent } from '../../parser/percent';
import type { TSize } from '../../typedefs';
import type { GradientCoords, GradientType, GradientUnits } from '../typedefs';
import { parseGradientUnits, parseType } from './misc';

function convertPercentUnitsToValues<
  T extends GradientType,
  K extends keyof GradientCoords<T>,
>(
  valuesToConvert: Record<K, string | number>,
  { width, height, gradientUnits }: TSize & { gradientUnits: GradientUnits },
) {
  let finalValue;
  return (Object.entries(valuesToConvert) as [K, string | number][]).reduce(
    (acc, [prop, propValue]) => {
      if (propValue === 'Infinity') {
        finalValue = 1;
      } else if (propValue === '-Infinity') {
        finalValue = 0;
      } else {
        const isString = typeof propValue === 'string';
        finalValue = isString ? parseFloat(propValue) : propValue;
        if (isString && isPercent(propValue)) {
          finalValue *= 0.01;
          if (gradientUnits === 'pixels') {
            // then we need to fix those percentages here in svg parsing
            if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
              finalValue *= width;
            }
            if (prop === 'y1' || prop === 'y2') {
              finalValue *= height;
            }
          }
        }
      }
      acc[prop] = finalValue;
      return acc;
    },
    {} as Record<K, number>,
  );
}

function getValue(el: SVGGradientElement, key: string) {
  return el.getAttribute(key);
}

export function parseLinearCoords(el: SVGGradientElement) {
  return {
    x1: getValue(el, 'x1') || 0,
    y1: getValue(el, 'y1') || 0,
    x2: getValue(el, 'x2') || '100%',
    y2: getValue(el, 'y2') || 0,
  };
}

export function parseRadialCoords(el: SVGGradientElement) {
  return {
    x1: getValue(el, 'fx') || getValue(el, 'cx') || '50%',
    y1: getValue(el, 'fy') || getValue(el, 'cy') || '50%',
    r1: 0,
    x2: getValue(el, 'cx') || '50%',
    y2: getValue(el, 'cy') || '50%',
    r2: getValue(el, 'r') || '50%',
  };
}

export function parseCoords(el: SVGGradientElement, size: TSize) {
  return convertPercentUnitsToValues(
    parseType(el) === 'linear' ? parseLinearCoords(el) : parseRadialCoords(el),
    {
      ...size,
      gradientUnits: parseGradientUnits(el),
    },
  );
}
