import type { AtRule, Plugin } from 'postcss'
import type { Config } from 'tailwindcss'
import type { DesignSystem } from '../../../tailwindcss/src/design-system'
import { segment } from '../../../tailwindcss/src/utils/segment'
import { migrateCandidate } from '../template/migrate'

export function migrateAtApply({
  designSystem,
  userConfig,
}: {
  designSystem: DesignSystem
  userConfig: Config
}): Plugin {
  function migrate(atRule: AtRule) {
    let utilities = atRule.params.split(/(\s+)/)
    let important =
      utilities[utilities.length - 1] === '!important' ||
      utilities[utilities.length - 1] === '#{!important}' // Sass/SCSS

    if (important) utilities.pop() // Remove `!important`

    let params = utilities.map((part) => {
      // Keep whitespace
      if (part.trim() === '') return part
      let variants = segment(part, ':')
      let utility = variants.pop()!

      // Apply the important modifier to all the rules if necessary
      if (important && utility[0] !== '!' && utility[utility.length - 1] !== '!') {
        utility += '!'
      }

      // Reconstruct the utility with the variants
      return [...variants, utility].join(':')
    })

    // If we have a valid designSystem and config setup, we can run all
    // candidate migrations on each utility
    params = params.map((param) => migrateCandidate(designSystem, userConfig, param))

    atRule.params = params.join('').trim()
  }

  return {
    postcssPlugin: '@tailwindcss/upgrade/migrate-at-apply',
    OnceExit(root) {
      root.walkAtRules('apply', migrate)
    },
  }
}