import type { Dictionary } from 'style-dictionary/types'

import { describe, expect, it } from 'vitest'

import { formatTailwindPlugin } from './tailwind-plugin.mjs'

describe('format/TailwindPlugin', () => {
  describe('Atomic tokens', () => {
    it('should write variables with no references', async () => {
      const dictionary = {
        allTokens: [
          {
            name: 'color-primary',
            $value: '#FF0000',
            original: { $value: '#FF0000' },
          },
          {
            name: 'color-secondary',
            $value: '#00FF00',
            original: { $value: '#00FF00' },
          },
        ],
      } as Dictionary

      const options = {
        name: 'myPlugin',
        outputReferences: false,
      }

      const result = await formatTailwindPlugin({
        dictionary,
        options,
      } as any)

      expect(result).toMatchInlineSnapshot(`
        "import plugin from "tailwindcss/plugin";

        const myPluginTailwindPlugin = plugin(({ addBase }) => {
          // Add CSS variables
          addBase({
            ":root": { "--color-primary": "#FF0000", "--color-secondary": "#00FF00" },
          });

          // Add base styles
          addBase({
            "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
            ol: { listStyleType: "decimal" },
            ul: { listStyleType: "disc" },
          });
        });
        "
      `)
    })

    it('should write variables with correct references', async () => {
      const dictionary = {
        allTokens: [
          {
            name: 'color-red',
            $value: '#FF0000',
            original: { $value: '#FF0000' },
          },
          {
            name: 'color-primary',
            $value: '{color.red}',
            original: { $value: '{color.red}' },
          },
        ],
        tokens: {
          color: {
            red: { $value: '#FF0000', name: 'color-red' },
            primary: { $value: '{color.red}', name: 'color-primary' },
          },
        },
      } as unknown as Dictionary

      const options = {
        name: 'myPlugin',
        outputReferences: true,
        usesDtcg: true,
      }

      const result = await formatTailwindPlugin({
        dictionary,
        options,
      } as any)

      expect(result).toMatchInlineSnapshot(`
        "import plugin from "tailwindcss/plugin";

        const myPluginTailwindPlugin = plugin(({ addBase }) => {
          // Add CSS variables
          addBase({
            ":root": {
              "--color-red": "#FF0000",
              "--color-primary": "var(--color-red)",
            },
          });

          // Add base styles
          addBase({
            "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
            ol: { listStyleType: "decimal" },
            ul: { listStyleType: "disc" },
          });
        });
        "
      `)
    })
  })

  describe('Composite tokens', () => {
    describe('Font Family', () => {
      it('should concatenate font family array values with proper quotes', async () => {
        const dictionary = {
          allTokens: [
            {
              name: 'font-family-sans',
              $type: 'fontFamily',
              $value: ['Arial', 'Segoe UI', 'sans-serif'],
              original: { $value: ['Arial', 'Segoe UI', 'sans-serif'] },
            },
          ],
        } as Dictionary

        const options = {
          name: 'myPlugin',
          outputReferences: false,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase }) => {
            // Add CSS variables
            addBase({
              ":root": { "--font-family-sans": '"Arial", "Segoe UI", sans-serif' },
            });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });
          });
          "
        `)
      })

      it('should handle single font family value', async () => {
        const dictionary = {
          allTokens: [
            {
              name: 'font-family-primary',
              $type: 'fontFamily',
              $value: 'Inter',
              original: { $value: 'Inter' },
            },
          ],
        } as Dictionary

        const options = {
          name: 'myPlugin',
          outputReferences: false,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase }) => {
            // Add CSS variables
            addBase({ ":root": { "--font-family-primary": '"Inter"' } });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });
          });
          "
        `)
      })
    })

    describe('Typography', () => {
      const dictionary = {
        allTokens: [
          {
            name: 'typography-h1',
            $type: 'typography',
            $value: {
              fontFamily: '{font.family.sans}',
              fontSize: '{font.size.600}',
              fontWeight: '{font.weight.medium}',
              lineHeight: 1.104,
            },
            original: {
              $value: {
                fontFamily: '{font.family.sans}',
                fontSize: '{font.size.600}',
                fontWeight: '{font.weight.medium}',
                lineHeight: 1.104,
              },
            },
          },
          {
            name: 'typography-body',
            $type: 'typography',
            $value: {
              fontFamily: 'Arial',
              fontSize: '16px',
              fontWeight: '400',
              lineHeight: 1.5,
            },
            original: {
              $value: {
                fontFamily: 'Arial',
                fontSize: '16px',
                fontWeight: '400',
                lineHeight: 1.5,
              },
            },
          },
        ],
        tokens: {
          font: {
            family: {
              sans: {
                $value: 'Inter',
                name: 'font-family-sans',
                original: { $value: 'Inter' },
              },
            },
            size: {
              600: {
                $value: '29px',
                name: 'font-size-600',
                original: { $value: '29px' },
              },
            },
            weight: {
              medium: {
                $value: '500',
                name: 'font-weight-medium',
                original: { $value: '500' },
              },
            },
          },
        },
      } as unknown as Dictionary

      it('should write variables with references', async () => {
        const options = {
          name: 'myPlugin',
          outputReferences: true,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase, addComponents }) => {
            // Add CSS variables
            addBase({
              ":root": {
                "--typography-h1__font-family": "var(--font-family-sans)",
                "--typography-h1__font-size": "var(--font-size-600)",
                "--typography-h1__font-weight": "var(--font-weight-medium)",
                "--typography-h1__line-height": "1.104",
                "--typography-body__font-family": "Arial",
                "--typography-body__font-size": "16px",
                "--typography-body__font-weight": "400",
                "--typography-body__line-height": "1.5",
              },
            });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });

            addComponents({
              ".typography-h1": {
                font: "normal var(--typography-h1__font-weight) var(--typography-h1__font-size) / var(--typography-h1__line-height) var(--typography-h1__font-family)",
              },
              ".typography-body": {
                font: "normal var(--typography-body__font-weight) var(--typography-body__font-size) / var(--typography-body__line-height) var(--typography-body__font-family)",
              },
            });
          });
          "
        `)
      })

      it('should write variables without references', async () => {
        const options = {
          name: 'myPlugin',
          outputReferences: false,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase, addComponents }) => {
            // Add CSS variables
            addBase({
              ":root": {
                "--typography-h1__font-family": "{font.family.sans}",
                "--typography-h1__font-size": "{font.size.600}",
                "--typography-h1__font-weight": "{font.weight.medium}",
                "--typography-h1__line-height": "1.104",
                "--typography-body__font-family": "Arial",
                "--typography-body__font-size": "16px",
                "--typography-body__font-weight": "400",
                "--typography-body__line-height": "1.5",
              },
            });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });

            addComponents({
              ".typography-h1": {
                font: "normal var(--typography-h1__font-weight) var(--typography-h1__font-size) / var(--typography-h1__line-height) var(--typography-h1__font-family)",
              },
              ".typography-body": {
                font: "normal var(--typography-body__font-weight) var(--typography-body__font-size) / var(--typography-body__line-height) var(--typography-body__font-family)",
              },
            });
          });
          "
        `)
      })
    })

    describe('Layout grid', () => {
      const dictionary = {
        allTokens: [
          {
            name: 'layout-grid-xs-columns',
            $type: 'number',
            $value: 4,
            attributes: {
              category: 'layout',
              type: 'grid',
              item: 'xs',
              subitem: 'columns',
            },
            original: { $value: 4 },
          },
          {
            name: 'layout-grid-xs-gutter',
            $type: 'dimension',
            $value: '20px',
            attributes: {
              category: 'layout',
              type: 'grid',
              item: 'xs',
              subitem: 'gutter',
            },
            original: { $value: '{spacing.20}' },
          },
          {
            name: 'layout-grid-xs-margin',
            $type: 'dimension',
            $value: '20px',
            attributes: {
              category: 'layout',
              type: 'grid',
              item: 'xs',
              subitem: 'margin',
            },
            original: { $value: '{spacing.20}' },
          },
        ],
        tokens: {
          spacing: {
            20: {
              $value: '20px',
              name: 'spacing-20',
              original: { $value: '20px' },
            },
          },
        },
      } as unknown as Dictionary
      it('should write variables with references', async () => {
        const options = {
          name: 'myPlugin',
          outputReferences: true,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase, addComponents }) => {
            // Add CSS variables
            addBase({
              ":root": {
                "--layout-grid-xs__columns": "4",
                "--layout-grid-xs__gutter": "var(--spacing-20)",
                "--layout-grid-xs__margin": "var(--spacing-20)",
              },
            });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });

            addComponents({
              ".layout-grid-xs": {
                display: "grid",
                gridTemplateColumns: "repeat(var(--layout-grid-xs__columns), 1fr)",
                gridGap: "var(--layout-grid-xs__gutter)",
                margin: "0 var(--layout-grid-xs__margin)",
              },
            });
          });
          "
        `)
      })

      it('should write variables without references', async () => {
        const options = {
          name: 'myPlugin',
          outputReferences: false,
          usesDtcg: true,
        }

        const result = await formatTailwindPlugin({
          dictionary,
          options,
        } as any)

        expect(result).toMatchInlineSnapshot(`
          "import plugin from "tailwindcss/plugin";

          const myPluginTailwindPlugin = plugin(({ addBase, addComponents }) => {
            // Add CSS variables
            addBase({
              ":root": {
                "--layout-grid-xs__columns": "4",
                "--layout-grid-xs__gutter": "20px",
                "--layout-grid-xs__margin": "20px",
              },
            });

            // Add base styles
            addBase({
              "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
              ol: { listStyleType: "decimal" },
              ul: { listStyleType: "disc" },
            });

            addComponents({
              ".layout-grid-xs": {
                display: "grid",
                gridTemplateColumns: "repeat(var(--layout-grid-xs__columns), 1fr)",
                gridGap: "var(--layout-grid-xs__gutter)",
                margin: "0 var(--layout-grid-xs__margin)",
              },
            });
          });
          "
        `)
      })
    })
  })

  describe('Animations', () => {
    it('should write variables with no references', async () => {
      const dictionary = {
        allTokens: [
          {
            name: 'uy-animations-spin',
            $type: 'animation',
            $value: {
              name: 'spin',
              duration: { value: 2, unit: 's' },
              timingFunction: 'linear',
              iterationCount: 'infinite',
            },
            original: {
              $value: {
                name: 'spin',
                duration: { value: 2, unit: 's' },
                timingFunction: 'linear',
                iterationCount: 'infinite',
              },
            },
            path: ['animations', 'spin'],
            attributes: {
              category: 'animations',
              type: 'spin',
            },
          },
          {
            name: 'uy-keyframes-spin',
            $type: 'keyframes',
            $value: {
              '0%': {
                transform: 'rotate(0deg)',
              },
              '100%': {
                transform: 'rotate(360deg)',
              },
            },
            original: {
              $value: {
                '0%': {
                  transform: 'rotate(0deg)',
                },
                '100%': {
                  transform: 'rotate(360deg)',
                },
              },
            },
            path: ['keyframes', 'spin'],
            attributes: {
              category: 'animations',
              type: 'spin',
            },
          },
        ],
        tokens: {
          animations: {
            spin: {
              $value: {
                name: 'spin',
                duration: { value: 2, unit: 's' },
                timingFunction: 'linear',
                iterationCount: 'infinite',
              },
            },
          },
          keyframes: {
            spin: {
              $value: {
                '0%': {
                  transform: 'rotate(0deg)',
                },
                '100%': {
                  transform: 'rotate(360deg)',
                },
              },
            },
          },
        },
      } as unknown as Dictionary

      const options = {
        name: 'myPlugin',
        outputReferences: false,
        usesDtcg: true,
      }

      const result = await formatTailwindPlugin({
        dictionary,
        options,
      } as any)

      expect(result).toMatchInlineSnapshot(`
        "import plugin from "tailwindcss/plugin";

        const myPluginTailwindPlugin = plugin(({ addBase }) => {
          // Add CSS variables
          addBase({
            ":root": {
              "--uy-animations-spin-duration": "2s",
              "--uy-animations-spin-timing-function": "linear",
              "--uy-animations-spin-iteration-count": "infinite",
            },
          });

          // Add base styles
          addBase({
            "@keyframes spin": {
              "0%": { transform: "rotate(0deg)" },
              "100%": { transform: "rotate(360deg)" },
            },
            "b, strong": { fontWeight: "var(--uy-font-weight-bold)" },
            ol: { listStyleType: "decimal" },
            ul: { listStyleType: "disc" },
          });
        });
        "
      `)
    })
  })
})
