// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:csslib/src/messages.dart';
import 'package:test/test.dart';

import 'testing.dart';

void compileAndValidate(String input, String generated) {
  var errors = <Message>[];
  var stylesheet = compileCss(input, errors: errors, opts: simpleOptions);
  expect(errors.isEmpty, true, reason: errors.toString());
  expect(prettyPrint(stylesheet), generated);
}

void selectorVariations() {
  final input1 = r'''html { color: red; }''';
  final generated1 = r'''html {
  color: #f00;
}''';
  compileAndValidate(input1, generated1);

  final input2 = r'''button { span { height: 200 } }''';
  final generated2 = r'''button {
}
button span {
  height: 200;
}''';
  compileAndValidate(input2, generated2);

  final input3 = r'''div { color: red; } button { span { height: 200 } }''';
  final generated3 = r'''div {
  color: #f00;
}
button {
}
button span {
  height: 200;
}''';
  compileAndValidate(input3, generated3);

  final input4 = r'''#header { color: red; h1 { font-size: 26px; } }''';
  final generated4 = r'''#header {
  color: #f00;
}
#header h1 {
  font-size: 26px;
}''';
  compileAndValidate(input4, generated4);

  final input5 = r'''
#header {
  color: red;
  h1 { font-size: 26px; }
  background-color: blue;
}''';
  final generated5 = r'''#header {
  color: #f00;
  background-color: #00f;
}
#header h1 {
  font-size: 26px;
}''';
  compileAndValidate(input5, generated5);

  final input6 = r'''html { body {color: red; }}''';
  final generated6 = r'''html {
}
html body {
  color: #f00;
}''';
  compileAndValidate(input6, generated6);

  final input7 = r'''html body {color: red; }''';
  final generated7 = r'''html body {
  color: #f00;
}''';
  compileAndValidate(input7, generated7);

  final input8 = r'''
html, body { color: red; }
button { height: 200 }
body { width: 300px; }''';
  final generated8 = r'''html, body {
  color: #f00;
}
button {
  height: 200;
}
body {
  width: 300px;
}''';
  compileAndValidate(input8, generated8);

  final input9 = '''
html, body {
  color: red;
  button { height: 200 }
  div { width: 300px; }
}''';
  final generated9 = r'''html, body {
  color: #f00;
}
html button, body button {
  height: 200;
}
html div, body div {
  width: 300px;
}''';
  compileAndValidate(input9, generated9);

  final input10 = '''
html {
  color: red;
  button, div { height: 200 }
  body { width: 300px; }
}''';
  final generated10 = r'''html {
  color: #f00;
}
html button, html div {
  height: 200;
}
html body {
  width: 300px;
}''';
  compileAndValidate(input10, generated10);

  final input11 = '''
html, body {
  color: red;
  button, div { height: 200 }
  table { width: 300px; }
}''';
  final generated11 = r'''html, body {
  color: #f00;
}
html button, body button, html div, body div {
  height: 200;
}
html table, body table {
  width: 300px;
}''';
  compileAndValidate(input11, generated11);

  final input12 = '''
html, body {
  color: red;
  button, div {
    span, a, ul { height: 200 }
  }
  table { width: 300px; }
}''';
  final generated12 = r'''html, body {
  color: #f00;
}
'''
      'html button span, body button span, html div span, body div span, '
      'html button a, body button a, html div a, body div a, html button ul, '
      r'''body button ul, html div ul, body div ul {
  height: 200;
}
html table, body table {
  width: 300px;
}''';
  compileAndValidate(input12, generated12);

  final input13 = r'''
#header {
  div {
  width: 100px;
  a { height: 200px; }
  }
  color: blue;
}
span { color: #1f1f1f; }
''';
  final generated13 = r'''#header {
  color: #00f;
}
#header div {
  width: 100px;
}
#header div a {
  height: 200px;
}
span {
  color: #1f1f1f;
}''';
  compileAndValidate(input13, generated13);
}

void simpleNest() {
  final input = '''
div span { color: green; }
#header {
  color: red;
  h1 {
    font-size: 26px;
    font-weight: bold;
  }
  p {
    font-size: 12px;
    a {
      text-decoration: none;
    }
  }
  background-color: blue;
}
div > span[attr="foo"] { color: yellow; }
''';

  final generated = r'''div span {
  color: #008000;
}
#header {
  color: #f00;
  background-color: #00f;
}
#header h1 {
  font-size: 26px;
  font-weight: bold;
}
#header p {
  font-size: 12px;
}
#header p a {
  text-decoration: none;
}
div > span[attr="foo"] {
  color: #ff0;
}''';
  compileAndValidate(input, generated);
}

void complexNest() {
  final input = '''
@font-face { font-family: arial; }
div { color: #f0f0f0; }
#header + div {
  color: url(abc.png);
  *[attr="bar"] {
    font-size: 26px;
    font-weight: bold;
  }
  p~ul {
    font-size: 12px;
    :not(p) {
      text-decoration: none;
      div > span[attr="foo"] { color: yellow; }
    }
  }
  background-color: blue;
  span {
    color: red;
    .one { color: blue; }
    .two { color: green; }
    .three { color: yellow; }
    .four {
       .four-1 { background-color: #00000f; }
       .four-2 { background-color: #0000ff; }
       .four-3 { background-color: #000fff; }
       .four-4 {
         height: 44px;
         .four-4-1 { height: 10px; }
         .four-4-2 { height: 20px; }
         .four-4-3 { height: 30px; }
         width: 44px;
       }
    }
  }
}
span { color: #1f1f2f; }
''';

  final generated = r'''@font-face {
  font-family: arial;
}
div {
  color: #f0f0f0;
}
#header + div {
  color: url("abc.png");
  background-color: #00f;
}
#header + div *[attr="bar"] {
  font-size: 26px;
  font-weight: bold;
}
#header + div p ~ ul {
  font-size: 12px;
}
#header + div p ~ ul :not(p) {
  text-decoration: none;
}
#header + div p ~ ul :not(p) div > span[attr="foo"] {
  color: #ff0;
}
#header + div span {
  color: #f00;
}
#header + div span .one {
  color: #00f;
}
#header + div span .two {
  color: #008000;
}
#header + div span .three {
  color: #ff0;
}
#header + div span .four .four-1 {
  background-color: #00000f;
}
#header + div span .four .four-2 {
  background-color: #00f;
}
#header + div span .four .four-3 {
  background-color: #000fff;
}
#header + div span .four .four-4 {
  height: 44px;
  width: 44px;
}
#header + div span .four .four-4 .four-4-1 {
  height: 10px;
}
#header + div span .four .four-4 .four-4-2 {
  height: 20px;
}
#header + div span .four .four-4 .four-4-3 {
  height: 30px;
}
span {
  color: #1f1f2f;
}''';

  compileAndValidate(input, generated);
}

void mediaNesting() {
  final input = r'''
@media screen and (-webkit-min-device-pixel-ratio:0) {
  #toggle-all {
    image: url(test.jpb);
    div, table {
      background: none;
      a { width: 100px; }
    }
    color: red;
  }
}
''';
  final generated = r'''
@media screen AND (-webkit-min-device-pixel-ratio:0) {
  #toggle-all {
    image: url("test.jpb");
    color: #f00;
  }
  #toggle-all div, #toggle-all table {
    background: none;
  }
  #toggle-all div a, #toggle-all table a {
    width: 100px;
  }
}''';

  compileAndValidate(input, generated);
}

void simpleThis() {
  final input = '''#header {
  h1 {
    font-size: 26px;
    font-weight: bold;
  }
  p { font-size: 12px;
    a { text-decoration: none;
      &:hover { border-width: 1px }
    }
  }
}
''';

  final generated = r'''#header {
}
#header h1 {
  font-size: 26px;
  font-weight: bold;
}
#header p {
  font-size: 12px;
}
#header p a {
  text-decoration: none;
}
#header p a:hover {
  border-width: 1px;
}''';

  compileAndValidate(input, generated);
}

void complexThis() {
  final input1 = r'''
.light {
  .leftCol {
    .textLink {
      color: fooL1;
      &:hover { color: barL1;}
    }
    .picLink {
      background-image: url(/fooL1.jpg);
      &:hover { background-image: url(/barL1.jpg);}
    }
    .textWithIconLink {
      color: fooL2;
      background-image: url(/fooL2.jpg);
      &:hover { color: barL2; background-image: url(/barL2.jpg);}
    }
  }
}''';

  final generated1 = r'''.light {
}
.light .leftCol .textLink {
  color: fooL1;
}
.light .leftCol .textLink:hover {
  color: barL1;
}
.light .leftCol .picLink {
  background-image: url("/fooL1.jpg");
}
.light .leftCol .picLink:hover {
  background-image: url("/barL1.jpg");
}
.light .leftCol .textWithIconLink {
  color: fooL2;
  background-image: url("/fooL2.jpg");
}
.light .leftCol .textWithIconLink:hover {
  color: barL2;
  background-image: url("/barL2.jpg");
}''';

  compileAndValidate(input1, generated1);

  final input2 = r'''
.textLink {
  .light .leftCol & {
    color: fooL1;
    &:hover { color: barL1; }
  }
  .light .rightCol & {
    color: fooL3;
    &:hover { color: barL3; }
  }
}''';

  final generated2 = r'''
.textLink {
}
.light .leftCol .textLink {
  color: fooL1;
}
.light .leftCol .textLink:hover {
  color: barL1;
}
.light .rightCol .textLink {
  color: fooL3;
}
.light .rightCol .textLink:hover {
  color: barL3;
}''';

  compileAndValidate(input2, generated2);
}

void variationsThis() {
  final input1 = r'''
.textLink {
  a {
    light .leftCol & {
      color: red;
    }
  }
}''';
  final generated1 = r'''.textLink {
}
light .leftCol .textLink a {
  color: #f00;
}''';

  compileAndValidate(input1, generated1);

  final input2 = r'''.textLink {
  a {
    & light .leftCol & {
      color: red;
    }
  }
}''';
  final generated2 = r'''.textLink {
}
.textLink a light .leftCol .textLink a {
  color: #f00;
}''';
  compileAndValidate(input2, generated2);

  final input3 = r'''
.textLink {
  a {
    & light .leftCol { color: red; }
  }
}''';
  final generated3 = r'''.textLink {
}
.textLink a light .leftCol {
  color: #f00;
}''';
  compileAndValidate(input3, generated3);

  final input4 = r'''
.textLink {
  a {
    & light .leftCol { color: red; }
    &:hover { width: 100px; }
  }
}''';
  final generated4 = r'''.textLink {
}
.textLink a light .leftCol {
  color: #f00;
}
.textLink a:hover {
  width: 100px;
}''';
  compileAndValidate(input4, generated4);

  final input5 = r'''.textLink { a { &:hover { color: red; } } }''';
  final generated5 = r'''.textLink {
}
.textLink a:hover {
  color: #f00;
}''';

  compileAndValidate(input5, generated5);

  final input6 = r'''.textLink { &:hover { color: red; } }''';
  final generated6 = r'''.textLink {
}
.textLink:hover {
  color: #f00;
}''';
  compileAndValidate(input6, generated6);

  final input7 = r'''.textLink { a { & + & { color: red; } } }''';
  final generated7 = r'''.textLink {
}
.textLink a + .textLink a {
  color: #f00;
}''';
  compileAndValidate(input7, generated7);

  final input8 = r'''.textLink { a { & { color: red; } } }''';
  final generated8 = r'''.textLink {
}
.textLink a {
  color: #f00;
}''';
  compileAndValidate(input8, generated8);

  final input9 = r'''.textLink { a { & ~ & { color: red; } } }''';
  final generated9 = r'''.textLink {
}
.textLink a ~ .textLink a {
  color: #f00;
}''';
  compileAndValidate(input9, generated9);

  final input10 = r'''.textLink { a { & & { color: red; } } }''';
  final generated10 = r'''.textLink {
}
.textLink a .textLink a {
  color: #f00;
}''';
  compileAndValidate(input10, generated10);
}

void thisCombinator() {
  var input = r'''
.btn {
  color: red;
}
.btn + .btn {
  margin-left: 5px;
}
input.second {
  & + label {
    color: blue;
  }
}
''';

  var generated = r'''.btn {
  color: #f00;
}
.btn + .btn {
  margin-left: 5px;
}
input.second {
}
input.second + label {
  color: #00f;
}''';

  compileAndValidate(input, generated);
}

void main() {
  test('Selector and Nested Variations', selectorVariations);
  test('Simple nesting', simpleNest);
  test('Complex nesting', complexNest);
  test('@media nesting', mediaNesting);
  test('Simple &', simpleThis);
  test('Variations &', variationsThis);
  test('Complex &', complexThis);
  test('& with + selector', thisCombinator);
}
