type Data = {
  colors: Record<string, any>
  spacing: Record<string, any>
  effects: Record<string, any>
  borders: Record<string, any>
}

type Args = {
  activeSafeList: boolean
  data: Data
}

export function safelist({ activeSafeList = true, data }: Args): string[] {
  if (activeSafeList) {
    const colors = data.colors
      ? safelistElementColors(safelistColors(data.colors))
      : []
    const spacing = data.spacing ? safelistSpacing(data.spacing) : []

    const effects = safelistEffects(data.effects)

    const gaps = range(20).map((i) => `gap-${i}`)
    const gridRows = range(14).map((i) => `grid-rows-${i}`)
    const gridCols = range(14).map((i) => `grid-cols-${i}`)
    const rowsStart = range(14).map((i) => `row-start-${i}`)
    const colsStart = range(14).map((i) => `col-start-${i}`)
    const rowsSpan = range(14).map((i) => `row-span-${i}`)
    const colsSpan = range(14).map((i) => `col-span-${i}`)

    const maxLines = range(10).map((i) => `max-lines-${i}`)

    const borders = safelistBorders(data.borders.borderRadius, data.borders.borderWidth)

    return  [
      'debug',
      'debug-all',
      ...colors,
      ...spacing,
      ...gaps,
      ...gridRows,
      ...gridCols,
      ...rowsStart,
      ...colsStart,
      ...rowsSpan,
      ...colsSpan,
      ...effects,
      ...maxLines,
      ...borders,
      ...safelistTypography(),
      ...safelistIconSizes(),
      ...safelistIllustrationsSizes(),
    ]
  }

  return []
}

export function safelistColors({ colors, backgroundImage }: Data['colors']) {
  const colorsNames: string[] = []

  for (const category in colors) {
    for (const color in colors[category]) {
      const current = colors[category][color]

      if (typeof current === 'string') {
        colorsNames.push(`${category}-${color}`)
      }

      if (typeof current === 'object') {
        for (const insideColor in colors[category][color]) {
          colorsNames.push(`${category}-${color}-${insideColor}`)
        }
      }
    }
  }

  for (const gradientName in backgroundImage) {
    colorsNames.push(`${gradientName}`)
  }

  return colorsNames
}

export function safelistElementColors(colorsNames: string[]) {
  const elements = [
    'text',
    'bg',
    'outline',
    'fill',
    'stroke',
    'border',
    'shadow',
    'text-decoration-color',
    'text-stroke-color',
  ]

  const elementColors: string[] = []

  elements.forEach((element) => elementColors.push(`${element}-transparent`))

  elements.forEach((element: string) => {
    colorsNames.forEach((color: string) => {
      elementColors.push(`${element}-${color}`)
    })
  })

  return elementColors
}

export function safelistBorders(borderRadius: Data['spacing'], borderWidth: Data['spacing']): string[] {
  const borderAxis = [
    'border',
    'border-a',
    'border-x',
    'border-y',
    'border-l',
    'border-r',
    'border-t',
    'border-b',
  ]
  const borderWidthAxis = [
    'rounded',
    'rounded-x',
    'rounded-y',
    'rounded-l',
    'rounded-r',
    'rounded-t',
    'rounded-b',
  ]

  const elementsBorder: string[] = []


  Object.keys(borderWidth).forEach((element: string) => {
    borderAxis.forEach((axis) => {
      elementsBorder.push(`${axis}-${element}`)
    })
  })
  
  Object.keys(borderRadius).forEach((element: string) => {
    borderWidthAxis.forEach((axis) => {
      elementsBorder.push(`${axis}-${element}`)
    })
  })

  return elementsBorder
}

export function safelistSpacing(spacing: Data['spacing']): string[] {
  const spacingTokenNames = Object.keys(spacing)
  const paddings = ['p', 'px', 'py', 'pl', 'pr', 'pt', 'pb']
  const margins = ['m', 'mx', 'my', 'ml', 'mr', 'mt', 'mb']

  const typos = [
    'text',
    'tracking',
    'decoration',
    'underline-offset',
    'indent',
    'text-stroke',
  ]
  const svg = ['stroke']
  const border = [
    'border-a',
    'border-x',
    'border-y',
    'border-l',
    'border-r',
    'border-t',
    'border-b',
  ]

  const staticTokens = ['w-full', 'h-full', 'w-fit-content']

  const elements = [
    ...paddings,
    ...margins,
    ...typos,
    ...svg,
    ...border,
  ]

  const elementSpacing: string[] = staticTokens

  elements.forEach((element: string) => {
    spacingTokenNames.forEach((space: string) => {
      elementSpacing.push(`${element}-${space}`)
    })
  })

  margins.forEach((margin) => elementSpacing.push(`${margin}-auto`))
  paddings.forEach((padding) => elementSpacing.push(`${padding}-auto`))

  return elementSpacing
}

export function range(size: number, startAt = 1) {
  return Array.from(Array(size).keys()).map((i) => i + startAt)
}

export function safelistEffects(effects: Data['effects']) {
  const opacitiesPrefix = ['text', 'bg', 'shadow']

  const opacities = Object.keys(effects.opacity).flatMap((opacity) =>
    opacitiesPrefix.map((prefix) => `${prefix}-${opacity}`),
  )

  const shadows = Object.keys(effects.boxShadow).flatMap(
    (shadow) => `shadow-${shadow}`,
  )

  return [...opacities, ...shadows]
}

export function safelistIconSizes() {
  return [
    'icon-size-small',
    'icon-size-medium',
    'icon-size-large',
    'icon-size-x-large',
    'icon-size-giga',
  ]
}

export function safelistIllustrationsSizes() {
  return [
    'illustration-size-micro',
    'illustration-size-xs',
    'illustration-size-sm',
    'illustration-size-medium',
    'illustration-size-large',
    'illustration-size-xl',
    'illustration-size-2xl',
    'illustration-size-mega',
    'illustration-size-giga',
  ]
}

export function safelistTypography() {
  return [
    'fonts-display-large',
    'fonts-display-medium',
    'fonts-display-small',
    'fonts-heading-h1',
    'fonts-heading-h2',
    'fonts-heading-h3',
    'fonts-heading-h4',
    'fonts-body-x-large-regular',
    'fonts-body-x-large-bold',
    'fonts-body-large-regular',
    'fonts-body-large-bold',
    'fonts-body-medium-regular',
    'fonts-body-medium-bold',
    'fonts-body-small-regular',
    'fonts-body-small-bold',
    'fonts-link-inline-large',
    'fonts-link-inline-medium',
    'fonts-link-inline-small',
    'fonts-overline-small',
  ]
}
