import postcss from 'postcss'
import plugin from '../src/lib/substituteResponsiveAtRules'
import config from '../stubs/defaultConfig.stub.js'

function run(input, opts = config) {
  return postcss([plugin(opts)]).process(input, { from: undefined })
}

test('it can generate responsive variants', () => {
  const input = `
    @responsive {
      .banana { color: yellow; }
      .chocolate { color: brown; }
    }

    @tailwind screens;
  `

  const output = `
    .banana { color: yellow; }
    .chocolate { color: brown; }
    @media (min-width: 500px) {
      .sm\\:banana { color: yellow; }
      .sm\\:chocolate { color: brown; }
    }
    @media (min-width: 750px) {
      .md\\:banana { color: yellow; }
      .md\\:chocolate { color: brown; }
    }
    @media (min-width: 1000px) {
      .lg\\:banana { color: yellow; }
      .lg\\:chocolate { color: brown; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('it can generate responsive variants with a custom separator', () => {
  const input = `
    @responsive {
      .banana { color: yellow; }
      .chocolate { color: brown; }
    }

    @tailwind screens;
  `

  const output = `
    .banana { color: yellow; }
    .chocolate { color: brown; }
    @media (min-width: 500px) {
      .sm__banana { color: yellow; }
      .sm__chocolate { color: brown; }
    }
    @media (min-width: 750px) {
      .md__banana { color: yellow; }
      .md__chocolate { color: brown; }
    }
    @media (min-width: 1000px) {
      .lg__banana { color: yellow; }
      .lg__chocolate { color: brown; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: '__',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('it can generate responsive variants when classes have non-standard characters', () => {
  const input = `
    @responsive {
      .hover\\:banana { color: yellow; }
      .chocolate-2\\.5 { color: brown; }
      .group:hover .group-hover\\:toast { color: black; }
    }

    @tailwind screens;
    `

  const output = `
    .hover\\:banana { color: yellow; }
    .chocolate-2\\.5 { color: brown; }
    .group:hover .group-hover\\:toast { color: black; }
    @media (min-width: 500px) {
      .sm\\:hover\\:banana { color: yellow; }
      .sm\\:chocolate-2\\.5 { color: brown; }
      .group:hover .sm\\:group-hover\\:toast { color: black; }
      }
    @media (min-width: 750px) {
      .md\\:hover\\:banana { color: yellow; }
      .md\\:chocolate-2\\.5 { color: brown; }
      .group:hover .md\\:group-hover\\:toast { color: black; }
      }
    @media (min-width: 1000px) {
      .lg\\:hover\\:banana { color: yellow; }
      .lg\\:chocolate-2\\.5 { color: brown; }
      .group:hover .lg\\:group-hover\\:toast { color: black; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('responsive variants are grouped', () => {
  const input = `
    @responsive {
      .banana { color: yellow; }
    }

    .apple { color: red; }

    @responsive {
      .chocolate { color: brown; }
    }

    @tailwind screens;
  `

  const output = `
    .banana { color: yellow; }
    .apple { color: red; }
    .chocolate { color: brown; }
    @media (min-width: 500px) {
      .sm\\:banana { color: yellow; }
      .sm\\:chocolate { color: brown; }
    }
    @media (min-width: 750px) {
      .md\\:banana { color: yellow; }
      .md\\:chocolate { color: brown; }
    }
    @media (min-width: 1000px) {
      .lg\\:banana { color: yellow; }
      .lg\\:chocolate { color: brown; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('it can generate responsive variants for nested at-rules', () => {
  const input = `
    @responsive {
      .banana { color: yellow; }

      @supports(display: grid) {
        .grid\\:banana { color: blue; }
      }
    }

    @tailwind screens;
  `

  const output = `
    .banana {
      color: yellow;
    }

    @supports(display: grid) {
      .grid\\:banana {
        color: blue;
      }
    }

    @media (min-width: 500px) {
      .sm\\:banana {
        color: yellow;
      }

      @supports(display: grid) {
        .sm\\:grid\\:banana {
          color: blue;
        }
      }
    }

    @media (min-width: 1000px) {
      .lg\\:banana {
        color: yellow;
      }

      @supports(display: grid) {
        .lg\\:grid\\:banana {
          color: blue;
        }
      }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('it can generate responsive variants for deeply nested at-rules', () => {
  const input = `
    @responsive {
      .banana { color: yellow; }

      @supports(display: grid) {
        @supports(display: flex) {
          .flex-grid\\:banana { color: blue; }
        }
      }
    }

    @tailwind screens;
  `

  const output = `
    .banana {
      color: yellow;
    }

    @supports(display: grid) {
      @supports(display: flex) {
        .flex-grid\\:banana {
          color: blue;
        }
      }
    }

    @media (min-width: 500px) {
      .sm\\:banana {
        color: yellow;
      }

      @supports(display: grid) {
        @supports(display: flex) {
          .sm\\:flex-grid\\:banana {
            color: blue;
          }
        }
      }
    }

    @media (min-width: 1000px) {
      .lg\\:banana {
        color: yellow;
      }

      @supports(display: grid) {
        @supports(display: flex) {
          .lg\\:flex-grid\\:banana {
            color: blue;
          }
        }
      }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('screen prefix is only applied to the last class in a selector', () => {
  const input = `
    @responsive {
      .banana li * .sandwich #foo > div { color: yellow; }
    }

    @tailwind screens;
  `

  const output = `
    .banana li * .sandwich #foo > div { color: yellow; }
    @media (min-width: 500px) {
      .banana li * .sm\\:sandwich #foo > div { color: yellow; }
    }
    @media (min-width: 750px) {
      .banana li * .md\\:sandwich #foo > div { color: yellow; }
    }
    @media (min-width: 1000px) {
      .banana li * .lg\\:sandwich #foo > div { color: yellow; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('responsive variants are generated for all selectors in a rule', () => {
  const input = `
    @responsive {
      .foo, .bar { color: yellow; }
    }

    @tailwind screens;
  `

  const output = `
    .foo, .bar { color: yellow; }
    @media (min-width: 500px) {
      .sm\\:foo, .sm\\:bar { color: yellow; }
    }
    @media (min-width: 750px) {
      .md\\:foo, .md\\:bar { color: yellow; }
    }
    @media (min-width: 1000px) {
      .lg\\:foo, .lg\\:bar { color: yellow; }
    }
  `

  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).then((result) => {
    expect(result.css).toMatchCss(output)
    expect(result.warnings().length).toBe(0)
  })
})

test('selectors with no classes cannot be made responsive', () => {
  const input = `
    @responsive {
      div { color: yellow; }
    }

    @tailwind screens;
  `
  expect.assertions(1)
  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).catch((e) => {
    expect(e).toMatchObject({ name: 'CssSyntaxError' })
  })
})

test('all selectors in a rule must contain classes', () => {
  const input = `
    @responsive {
      .foo, div { color: yellow; }
    }

    @tailwind screens;
  `
  expect.assertions(1)
  return run(input, {
    theme: {
      screens: {
        sm: '500px',
        md: '750px',
        lg: '1000px',
      },
    },
    separator: ':',
  }).catch((e) => {
    expect(e).toMatchObject({ name: 'CssSyntaxError' })
  })
})
