import { generate, parse } from 'css-tree';
import { resolveAllCssVariables } from './resolve-all-css-variables.js';

describe('resolveAllCSSVariables', () => {
  it('ignores @layer (properties) defined for browser compatibility', () => {
    const root =
      parse(`/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
  :root, :host {
    --color-red-500: oklch(63.7% 0.237 25.331);
    --color-blue-400: oklch(70.7% 0.165 254.624);
    --color-blue-600: oklch(54.6% 0.245 262.881);
    --color-gray-200: oklch(92.8% 0.006 264.531);
    --color-black: #000;
    --color-white: #fff;
    --spacing: 0.25rem;
    --text-sm: 0.875rem;
    --text-sm--line-height: calc(1.25 / 0.875);
    --radius-md: 0.375rem;
  }
}
@layer utilities {
  .mt-8 {
    margin-top: calc(var(--spacing) * 8);
  }
  .rounded-md {
    border-radius: var(--radius-md);
  }
  .bg-blue-600 {
    background-color: var(--color-blue-600);
  }
  .bg-red-500 {
    background-color: var(--color-red-500);
  }
  .bg-white {
    background-color: var(--color-white);
  }
  .p-4 {
    padding: calc(var(--spacing) * 4);
  }
  .px-3 {
    padding-inline: calc(var(--spacing) * 3);
  }
  .py-2 {
    padding-block: calc(var(--spacing) * 2);
  }
  .text-sm {
    font-size: var(--text-sm);
    line-height: var(--tw-leading, var(--text-sm--line-height));
  }
  .text-\\\\[14px\\\\] {
    font-size: 14px;
  }
  .leading-\\\\[24px\\\\] {
    --tw-leading: 24px;
    line-height: 24px;
  }
  .text-black {
    color: var(--color-black);
  }
  .text-blue-400 {
    color: var(--color-blue-400);
  }
  .text-blue-600 {
    color: var(--color-blue-600);
  }
  .text-gray-200 {
    color: var(--color-gray-200);
  }
  .no-underline {
    text-decoration-line: none;
  }
}
@property --tw-leading {
  syntax: "*";
  inherits: false;
}
@layer properties {
  @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
    *, ::before, ::after, ::backdrop {
      --tw-leading: initial;
    }
  }
}
`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `"/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties;@layer theme,base,components,utilities;@layer theme{:root,:host{--color-red-500: oklch(63.7% 0.237 25.331);--color-blue-400: oklch(70.7% 0.165 254.624);--color-blue-600: oklch(54.6% 0.245 262.881);--color-gray-200: oklch(92.8% 0.006 264.531);--color-black: #000;--color-white: #fff;--spacing: 0.25rem;--text-sm: 0.875rem;--text-sm--line-height: calc(1.25 / 0.875);--radius-md: 0.375rem}}@layer utilities{.mt-8{margin-top:calc(0.25rem*8)}.rounded-md{border-radius:0.375rem}.bg-blue-600{background-color:oklch(54.6%0.245 262.881)}.bg-red-500{background-color:oklch(63.7%0.237 25.331)}.bg-white{background-color:#fff}.p-4{padding:calc(0.25rem*4)}.px-3{padding-inline:calc(0.25rem*3)}.py-2{padding-block:calc(0.25rem*2)}.text-sm{font-size:0.875rem;line-height:calc(1.25/0.875)}.text-\\\\[14px\\\\]{font-size:14px}.leading-\\\\[24px\\\\]{--tw-leading: 24px;line-height:24px}.text-black{color:#000}.text-blue-400{color:oklch(70.7%0.165 254.624)}.text-blue-600{color:oklch(54.6%0.245 262.881)}.text-gray-200{color:oklch(92.8%0.006 264.531)}.no-underline{text-decoration-line:none}}@property --tw-leading{syntax:"*";inherits:false}@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::before,::after,::backdrop{--tw-leading: initial}}}"`,
    );
  });

  it('works with simple css variables on a :root', () => {
    const root = parse(`:root {
  --width: 100px;
}

.box {
  width: var(--width);
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `":root{--width: 100px}.box{width:100px}"`,
    );
  });

  it('works for variables across different CSS layers', () => {
    const root = parse(`@layer base {
      :root {
        --width: 100px;
      }
    }

    @layer utilities {
      .box {
        width: var(--width);
      }
    }`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `"@layer base{:root{--width: 100px}}@layer utilities{.box{width:100px}}"`,
    );
  });

  it('works with multiple variables in the same declaration', () => {
    const root = parse(`:root {
      --top: 101px;
      --bottom: 102px;
      --right: 103px;
      --left: 104px;
    }

    .box {
      margin: var(--top) var(--right) var(--bottom) var(--left);
    }`);

    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `":root{--top: 101px;--bottom: 102px;--right: 103px;--left: 104px}.box{margin:101px 103px 102px 104px}"`,
    );
  });

  it('keeps variable usages if it cant find their declaration', () => {
    const root = parse(`.box {
  width: var(--width);
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(`".box{width:var(--width)}"`);
  });

  it('works with variables set in the same rule', () => {
    const root = parse(`.box {
  --width: 200px;
  width: var(--width);
}

@media (min-width: 1280px) {
  .xl\\\\:bg-green-500 {
    --tw-bg-opacity: 1;
    background-color: rgb(34 197 94 / var(--tw-bg-opacity))
  }
}
`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `".box{--width: 200px;width:200px}@media (min-width:1280px){.xl\\\\:bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94/1)}}"`,
    );
  });

  it('works with a variable set in a layer, and used in another through a media query', () => {
    const root = parse(`@layer theme {
  :root {
    --color-blue-300: blue;
  }
}

@layer utilities {
  .sm\\\\:bg-blue-300 {
    @media (width >= 40rem) {
      background-color: var(--color-blue-300);
    }
  }
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `"@layer theme{:root{--color-blue-300: blue}}@layer utilities{.sm\\\\:bg-blue-300{@media (width>=40rem){background-color:blue}}}"`,
    );
  });

  it('uses fallback values when variable definition is not found', () => {
    const root = parse(`.box {
  width: var(--undefined-width, 150px);
  height: var(--undefined-height, 200px);
  margin: var(--undefined-margin, 10px 20px);
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `".box{width:150px;height:200px;margin:10px 20px}"`,
    );
  });

  it('handles nested var() functions in fallbacks', () => {
    const root = parse(`:root {
  --fallback-width: 300px;
}

.box {
  width: var(--undefined-width, var(--fallback-width));
  height: var(--undefined-height, var(--also-undefined, 250px));
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `":root{--fallback-width: 300px}.box{width:300px;height:250px}"`,
    );
  });

  it('handles deeply nested var() functions with complex parentheses', () => {
    const root = parse(`:root {
  --primary: blue;
  --secondary: red;
  --fallback: green;
  --size: 20px;
}

.box {
  color: var(--primary, var(--secondary, var(--fallback)));
  width: var(--size, calc(100px + var(--size, 20px)));
  border: var(--border-width, var(--border-style, var(--border-color, 1px solid black)));
  --r: 100;
  --b: 10;
  background: var(--bg-color, rgb(var(--r, 255), var(--g, 0), var(--b, 0)));
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `":root{--primary: blue;--secondary: red;--fallback: green;--size: 20px}.box{color:blue;width:20px;border:1px solid black;--r: 100;--b: 10;background:rgb(100,0,10)}"`,
    );
  });

  it('does not leak variables across sibling nested at-rules within the same rule', () => {
    const root = parse(`.print_invert {
  @media print {
    --tw-invert: invert(100%);
    filter: var(--tw-invert, none);
  }
  @media screen {
    filter: var(--tw-invert, none);
  }
}`);
    resolveAllCssVariables(root);
    expect(generate(root)).toMatchInlineSnapshot(
      `".print_invert{@media print{--tw-invert: invert(100%);filter:invert(100%)}@media screen{filter:none}}"`,
    );
  });

  it('handles selectors with asterisks in attribute selectors and pseudo-functions', () => {
    const root = parse(`* {
  --global-color: red;
}

input[type="*"]:hover {
  color: var(--global-color);
}

div:nth-child(2*n+1) {
  background: var(--global-color);
}

.test[data-attr="value*test"] {
  border-color: var(--global-color);
}

.universal-with-class-* {
  --class-color: blue;
  text-decoration: var(--class-color);
}

.normal {
  color: var(--class-color);
}`);

    resolveAllCssVariables(root);
    const result = generate(root);

    // Variables from universal selector (*) should resolve to other selectors with actual universal selector
    expect(result).toContain('input[type="*"]:hover{color:red}');
    expect(result).toContain('div:nth-child(2*n+1){background:red}');
    expect(result).toContain('.test[data-attr="value*test"]{border-color:red}');

    // Variables from *.universal-with-class should resolve within the same selector and to .normal
    expect(result).toContain(
      '.universal-with-class-*{--class-color: blue;text-decoration:blue}',
    );
    expect(result).toContain('.normal{color:var(--class-color)}');
  });
});
