package parser

import (
	"bytes"
	"testing"

	"github.com/matryer/is"
)

func TestLexStylesMultilineComment(t *testing.T) {
	tests := []struct {
		input  TemplateBlockDataBuffer
		output StyleItem
	}{
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("/*Comment*/")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   "",
							Right:  "",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 10,
								Line:   1,
								Column: 11,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("/* Comment */")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   " ",
							Right:  " ",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 12,
								Line:   1,
								Column: 13,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("/*\nComment\n*/")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   "\n",
							Right:  "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 12,
								Line:   3,
								Column: 2,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("/*\n\tComment\n*/")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   "\n\t",
							Right:  "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 13,
								Line:   3,
								Column: 2,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("/**\n * Comment\n */")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STComment],
						Text: "*\n * Comment",
						Raws: RawType{
							Before: "",
							Left:   "",
							Right:  "\n ",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 17,
								Line:   3,
								Column: 3,
							},
						},
					},
				},
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := lexStyleBlock(tt.input)
		item := <-lexer.items

		// fmt.Printf("\n\n\n\nEXP: %+v\n\nRES: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexStylesInlineComment(t *testing.T) {
	tests := []struct {
		input  TemplateBlockDataBuffer
		output StyleItem
	}{
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("//Comment")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STInlineComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   "",
							Right:  "",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 9,
								Line:   1,
								Column: 9,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("// Comment")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STInlineComment],
						Text: "Comment",
						Raws: RawType{
							Before: "",
							Left:   " ",
							Right:  "",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 10,
								Line:   1,
								Column: 10,
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("// Single line comment")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:  StyleItemType[STInlineComment],
						Text: "Single line comment",
						Raws: RawType{
							Before: "",
							Left:   " ",
							Right:  "",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 22,
								Line:   1,
								Column: 22,
							},
						},
					},
				},
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := lexStyleBlock(tt.input)
		item := <-lexer.items

		// fmt.Printf("\n\n\n\nEXP: %+v\n\nRES: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexStylesRuleWithDecl(t *testing.T) {
	tests := []struct {
		input  TemplateBlockDataBuffer
		output StyleItem
	}{
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: true,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 18,
								Line:   3,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 12,
									},
								},
								Prop:  "color",
								Value: "red",
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: false,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 17,
								Line:   3,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 11,
									},
								},
								Prop:  "color",
								Value: "red",
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n\ttext-align: center;\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: true,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 39,
								Line:   4,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 12,
									},
								},
								Prop:  "color",
								Value: "red",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 19,
										Line:   3,
										Column: 2,
									},
									End: SourceData{
										Offset: 37,
										Line:   3,
										Column: 20,
									},
								},
								Prop:  "text-align",
								Value: "center",
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n\ttext-align: center\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{
					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: false,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 38,
								Line:   4,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 12,
									},
								},
								Prop:  "color",
								Value: "red",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 19,
										Line:   3,
										Column: 2,
									},
									End: SourceData{
										Offset: 36,
										Line:   3,
										Column: 19,
									},
								},
								Prop:  "text-align",
								Value: "center",
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n\ttext-align: center;\n\tbackground: blue;\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{

					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: true,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 58,
								Line:   5,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 12,
									},
								},
								Prop:  "color",
								Value: "red",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 19,
										Line:   3,
										Column: 2,
									},
									End: SourceData{
										Offset: 37,
										Line:   3,
										Column: 20,
									},
								},
								Prop:  "text-align",
								Value: "center",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 40,
										Line:   4,
										Column: 2,
									},
									End: SourceData{
										Offset: 56,
										Line:   4,
										Column: 18,
									},
								},
								Prop:  "background",
								Value: "blue",
							},
						},
					},
				},
			},
		},
		{
			input: TemplateBlockDataBuffer{
				Attrs: TemplateBlockAttrs{},
				Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n\ttext-align: center;\n\tbackground: blue\n}")),
			},
			output: StyleItem{
				Typ: StyleItemType[STRoot],
				Source: SourceType{
					Start: SourceData{
						Offset: 0,
						Line:   1,
						Column: 1,
					},
				},
				Nodes: []StyleItem{

					{
						Typ:      StyleItemType[STRule],
						Selector: "h1",
						Raws: RawType{
							Before:    "",
							Between:   " ",
							Semicolon: false,
							After:     "\n",
						},
						Source: SourceType{
							Start: SourceData{
								Offset: 0,
								Line:   1,
								Column: 1,
							},
							End: SourceData{
								Offset: 57,
								Line:   5,
								Column: 1,
							},
						},
						Nodes: []StyleItem{
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 6,
										Line:   2,
										Column: 2,
									},
									End: SourceData{
										Offset: 16,
										Line:   2,
										Column: 12,
									},
								},
								Prop:  "color",
								Value: "red",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 19,
										Line:   3,
										Column: 2,
									},
									End: SourceData{
										Offset: 37,
										Line:   3,
										Column: 20,
									},
								},
								Prop:  "text-align",
								Value: "center",
							},
							{
								Typ: StyleItemType[STDecl],
								Raws: RawType{
									Before:  "\n\t",
									Between: ": ",
								},
								Source: SourceType{
									Start: SourceData{
										Offset: 40,
										Line:   4,
										Column: 2,
									},
									End: SourceData{
										Offset: 55,
										Line:   4,
										Column: 17,
									},
								},
								Prop:  "background",
								Value: "blue",
							},
						},
					},
				},
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := lexStyleBlock(tt.input)
		item := <-lexer.items

		// fmt.Printf("\n\n\n\nEXP: %+v\n\nRES: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexStylesNestedRulesWithDecl(t *testing.T) {
	tests := []struct {
		input  TemplateBlockDataBuffer
		output *StyleItem
	}{
		// {
		// 	input: TemplateBlockDataBuffer{
		// 		Attrs: TemplateBlockAttrs{},
		// 		Data:  *bytes.NewBuffer([]byte("h1 {\n\tcolor: red;\n\n\tspan {\n\t\ttext-align: center;\n\t}\n}")),
		// 	},
		// 	output: &StyleItem{
		// 		Typ:      StyleItemType[STRule],
		// 		Selector: "h1",
		// 		Raws: RawType{
		// 			Before:    "",
		// 			Between:   " ",
		// 			Semicolon: false,
		// 			After:     "\n",
		// 		},
		// 		Source: SourceType{
		// 			Start: SourceData{
		// 				Offset: 0,
		// 				Line:   1,
		// 				Column: 1,
		// 			},
		// 			End: SourceData{
		// 				Offset: 58,
		// 				Line:   7,
		// 				Column: 1,
		// 			},
		// 		},
		// 		Nodes: []StyleItem{
		// 			{
		// 				Typ: StyleItemType[STDecl],
		// 				Raws: RawType{
		// 					Before:  "\n\t",
		// 					Between: ": ",
		// 				},
		// 				Source: SourceType{
		// 					Start: SourceData{
		// 						Offset: 6,
		// 						Line:   2,
		// 						Column: 2,
		// 					},
		// 					End: SourceData{
		// 						Offset: 16,
		// 						Line:   2,
		// 						Column: 12,
		// 					},
		// 				},
		// 				Prop:  "color",
		// 				Value: "red",
		// 			},
		// 			{
		// 				Typ:      StyleItemType[STRule],
		// 				Selector: "span",
		// 				Raws: RawType{
		// 					Before:    "\n\t",
		// 					Between:   " ",
		// 					Semicolon: true,
		// 					After:     "\n\t",
		// 				},
		// 				Source: SourceType{
		// 					Start: SourceData{
		// 						Offset: 20,
		// 						Line:   4,
		// 						Column: 2,
		// 					},
		// 					End: SourceData{
		// 						Offset: 54,
		// 						Line:   6,
		// 						Column: 2,
		// 					},
		// 				},
		// 				Nodes: []StyleItem{
		// 					{
		// 						Typ: StyleItemType[STDecl],
		// 						Raws: RawType{
		// 							Before:  "\n\t\t",
		// 							Between: ": ",
		// 						},
		// 						Source: SourceType{
		// 							Start: SourceData{
		// 								Offset: 29,
		// 								Line:   5,
		// 								Column: 3,
		// 							},
		// 							End: SourceData{
		// 								Offset: 47,
		// 								Line:   5,
		// 								Column: 21,
		// 							},
		// 						},
		// 						Prop:  "text-align",
		// 						Value: "center",
		// 					},
		// 				},
		// 			},
		// 		},
		// 	},
		// },
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := lexStyleBlock(tt.input)
		item := <-lexer.items

		pi := &StyleItem{}

		printStyleToken(pi, tt.output)

		// fmt.Printf("\n\n\n\nEXP: %+v\n\nRES: %+v\n\n", *pi, item)
		is.Equal(*pi, item)
	}
}
