package tfdiags

import (
	"fmt"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/hashicorp/hcl/v2"
)

func TestConsolidateWarnings(t *testing.T) {
	var diags Diagnostics

	for i := 0; i < 4; i++ {
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagWarning,
			Summary:  "Warning 1",
			Detail:   fmt.Sprintf("This one has a subject %d", i),
			Subject: &hcl.Range{
				Filename: "foo.tf",
				Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
				End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
			},
		})
		diags = diags.Append(&hcl.Diagnostic{
			Severity: hcl.DiagError,
			Summary:  "Error 1",
			Detail:   fmt.Sprintf("This one has a subject %d", i),
			Subject: &hcl.Range{
				Filename: "foo.tf",
				Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
				End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
			},
		})
		diags = diags.Append(Sourceless(
			Warning,
			"Warning 2",
			fmt.Sprintf("This one is sourceless %d", i),
		))
		diags = diags.Append(SimpleWarning("Warning 3"))
	}

	diags = diags.Append(&hcl.Diagnostic{
		Severity: hcl.DiagWarning,
		Summary:  "Warning 4",
		Detail:   "Only one of this one",
		Subject: &hcl.Range{
			Filename: "foo.tf",
			Start:    hcl.Pos{Line: 1, Column: 1, Byte: 0},
			End:      hcl.Pos{Line: 1, Column: 1, Byte: 0},
		},
	})

	// We're using ForRPC here to force the diagnostics to be of a consistent
	// type that we can easily assert against below.
	got := diags.ConsolidateWarnings().ForRPC()
	want := Diagnostics{
		// First set
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 1",
			Detail_:   "This one has a subject 0",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Error,
			Summary_:  "Error 1",
			Detail_:   "This one has a subject 0",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 2",
			Detail_:   "This one is sourceless 0",
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 3",
		},

		// Second set (consolidation begins; note additional paragraph in Warning 1 detail)
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 1",
			Detail_:   "This one has a subject 1\n\n(and 2 more similar warnings elsewhere)",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Error,
			Summary_:  "Error 1",
			Detail_:   "This one has a subject 1",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 2",
			Detail_:   "This one is sourceless 1",
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 3",
		},

		// Third set (no more Warning 1, because it's consolidated)
		&rpcFriendlyDiag{
			Severity_: Error,
			Summary_:  "Error 1",
			Detail_:   "This one has a subject 2",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 2",
			Detail_:   "This one is sourceless 2",
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 3",
		},

		// Fourth set (still no warning 1)
		&rpcFriendlyDiag{
			Severity_: Error,
			Summary_:  "Error 1",
			Detail_:   "This one has a subject 3",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 2",
			Detail_:   "This one is sourceless 3",
		},
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 3",
		},

		// Special straggler warning gets to show up unconsolidated, because
		// there is only one of it.
		&rpcFriendlyDiag{
			Severity_: Warning,
			Summary_:  "Warning 4",
			Detail_:   "Only one of this one",
			Subject_: &SourceRange{
				Filename: "foo.tf",
				Start:    SourcePos{Line: 1, Column: 1, Byte: 0},
				End:      SourcePos{Line: 1, Column: 1, Byte: 0},
			},
		},
	}

	if diff := cmp.Diff(want, got); diff != "" {
		t.Errorf("wrong result\n%s", diff)
	}
}
