// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package cloud

import (
	"strings"
	"testing"

	"github.com/hashicorp/go-tfe"
)

func TestCloud_runTaskStageWithPolicyEvaluation(t *testing.T) {
	b, bCleanup := testBackendWithName(t)
	defer bCleanup()

	integrationContext, writer := newMockIntegrationContext(b, t)

	cases := map[string]struct {
		taskStage       func() *tfe.TaskStage
		context         *IntegrationContext
		writer          *testIntegrationOutput
		expectedOutputs []string
		isError         bool
	}{
		"all-succeeded": {
			taskStage: func() *tfe.TaskStage {
				ts := &tfe.TaskStage{}
				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
					{ID: "pol-pass", ResultCount: &tfe.PolicyResultCount{Passed: 1}, Status: "passed"},
				}
				return ts
			},
			writer:          writer,
			context:         integrationContext,
			expectedOutputs: []string{"│ [bold]OPA Policy Evaluation\n\n│ [bold]→→ Overall Result: [green]PASSED\n│ [dim] This result means that all OPA policies passed and the protected behavior is allowed\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-passes (1)\n│   ↳ Policy name: [bold]policy-pass\n│      | [green][bold]✓ Passed\n│      | [dim]This policy will pass\n"},
			isError:         false,
		},
		"mandatory-failed": {
			taskStage: func() *tfe.TaskStage {
				ts := &tfe.TaskStage{}
				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
					{ID: "pol-fail", ResultCount: &tfe.PolicyResultCount{MandatoryFailed: 1}, Status: "failed"},
				}
				return ts
			},
			writer:          writer,
			context:         integrationContext,
			expectedOutputs: []string{"│ [bold]→→ Overall Result: [red]FAILED\n│ [dim] This result means that one or more OPA policies failed. More than likely, this was due to the discovery of violations by the main rule and other sub rules\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-fails (1)\n│   ↳ Policy name: [bold]policy-fail\n│      | [red][bold]× Failed\n│      | [dim]This policy will fail"},
			isError:         true,
		},
		"advisory-failed": {
			taskStage: func() *tfe.TaskStage {
				ts := &tfe.TaskStage{}
				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
					{ID: "adv-fail", ResultCount: &tfe.PolicyResultCount{AdvisoryFailed: 1}, Status: "failed"},
				}
				return ts
			},
			writer:          writer,
			context:         integrationContext,
			expectedOutputs: []string{"│ [bold]OPA Policy Evaluation\n\n│ [bold]→→ Overall Result: [red]FAILED\n│ [dim] This result means that one or more OPA policies failed. More than likely, this was due to the discovery of violations by the main rule and other sub rules\n│ 1 policies evaluated\n\n│ → Policy set 1: [bold]policy-set-that-fails (1)\n│   ↳ Policy name: [bold]policy-fail\n│      | [blue][bold]Ⓘ Advisory\n│      | [dim]This policy will fail"},
			isError:         false,
		},
		"unreachable": {
			taskStage: func() *tfe.TaskStage {
				ts := &tfe.TaskStage{}
				ts.PolicyEvaluations = []*tfe.PolicyEvaluation{
					{ID: "adv-fail", ResultCount: &tfe.PolicyResultCount{Errored: 1}, Status: "unreachable"},
				}
				return ts
			},
			writer:          writer,
			context:         integrationContext,
			expectedOutputs: []string{"Skipping policy evaluation."},
			isError:         false,
		},
	}

	for name, c := range cases {
		t.Run(name, func(t *testing.T) {
			c.writer.output.Reset()
			trs := policyEvaluationSummarizer{
				cloud: b,
			}
			err := c.context.Poll(0, 0, func(i int) (bool, error) {
				cont, _, _ := trs.Summarize(c.context, c.writer, c.taskStage())
				if cont {
					return true, nil
				}

				output := c.writer.output.String()
				for _, expected := range c.expectedOutputs {
					// Added this sanitisation of the expected while we removed the colorize object from the
					// outputs collector (testIntegrationOutput)
					expected = removeColoriseMarks(strings.ReplaceAll(expected, "│ ", ""))
					if !strings.Contains(output, expected) {
						t.Fatalf("Wrong output:\n\n%s\n\nExpected to contain:\n\n%s", output, expected)
					}
				}
				return false, nil
			})
			if err != nil {
				t.Fatalf("Error while polling: %v", err)
			}
		})
	}
}
