package job

import (
	"bytes"
	"context"
	"errors"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/metrics-integration/global/internal/domain/entity"
)

func TestBuildRedeployRegionRequest(t *testing.T) {
	req, err := buildRedeployRegionRequest(redeployRegionOptions{
		Cloud:               "AliCloud",
		Regions:             []string{" cn-hongkong ", "ap-southeast-1", "cn-hongkong"},
		PipelineIDAllowlist: "9, 3,9",
		PipelineIDBlocklist: "7",
		Apply:               true,
	})
	require.NoError(t, err)
	require.Equal(t, entity.IntegrationCloudProviderTypeAlibabaCloud, req.Cloud)
	require.Equal(t, []string{"ap-southeast-1", "cn-hongkong"}, req.Regions)
	require.Equal(t, []uint64{3, 9}, req.PipelineIDAllowlist)
	require.Equal(t, []uint64{7}, req.PipelineIDBlocklist)
	require.True(t, req.Apply)
}

func TestBuildRedeployRegionRequestRejectsInvalidInput(t *testing.T) {
	testCases := []struct {
		name string
		opts redeployRegionOptions
		err  string
	}{
		{
			name: "unsupported cloud",
			opts: redeployRegionOptions{Cloud: "other", Regions: []string{"us-west-2"}},
			err:  "unsupported cloud",
		},
		{
			name: "missing regions",
			opts: redeployRegionOptions{Cloud: "aws"},
			err:  "at least one region is required",
		},
		{
			name: "invalid region",
			opts: redeployRegionOptions{Cloud: "aws", Regions: []string{"us-west-2;rm"}},
			err:  "invalid region",
		},
		{
			name: "all regions is not allowed",
			opts: redeployRegionOptions{Cloud: "aws", Regions: []string{"all"}},
			err:  "explicit region names are required",
		},
		{
			name: "invalid allowlist",
			opts: redeployRegionOptions{
				Cloud:               "aws",
				Regions:             []string{"us-west-2"},
				PipelineIDAllowlist: "0",
			},
			err: "invalid pipeline ID allowlist",
		},
	}

	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			_, err := buildRedeployRegionRequest(testCase.opts)
			require.ErrorContains(t, err, testCase.err)
		})
	}
}

func TestExecuteRegionalRedeployPlanOnly(t *testing.T) {
	req := redeployRegionRequest{
		Cloud:   entity.IntegrationCloudProviderTypeAWS,
		Regions: []string{"us-west-2"},
	}
	pipelines := []entity.Integration{{
		Updatable:    entity.Updatable{Base: entity.Base{ID: 12}},
		Region:       "us-west-2",
		ProviderType: entity.IntegrationTypeDatadog,
		Status:       entity.IntegrationStatusActive,
	}}
	called := false
	var output bytes.Buffer

	err := executeRegionalRedeploy(
		context.Background(),
		&output,
		req,
		func(got redeployRegionRequest) ([]entity.Integration, error) {
			require.Equal(t, req, got)
			return pipelines, nil
		},
		func(context.Context, *entity.Integration) error {
			called = true
			return nil
		},
	)

	require.NoError(t, err)
	require.False(t, called)
	require.Contains(t, output.String(), "pipeline=12")
	require.Contains(t, output.String(), "Plan only")
}

func TestExecuteRegionalRedeployContinuesAfterFailure(t *testing.T) {
	req := redeployRegionRequest{
		Cloud:   entity.IntegrationCloudProviderTypeGCP,
		Regions: []string{"asia-northeast1"},
		Apply:   true,
	}
	pipelines := []entity.Integration{
		{Updatable: entity.Updatable{Base: entity.Base{ID: 21}}, Region: "asia-northeast1"},
		{Updatable: entity.Updatable{Base: entity.Base{ID: 22}}, Region: "asia-northeast1"},
	}
	called := make([]uint64, 0, len(pipelines))
	var output bytes.Buffer

	err := executeRegionalRedeploy(
		context.Background(),
		&output,
		req,
		func(redeployRegionRequest) ([]entity.Integration, error) {
			return pipelines, nil
		},
		func(_ context.Context, pipeline *entity.Integration) error {
			called = append(called, uint64(pipeline.ID))
			if pipeline.ID == 21 {
				return errors.New("test failure")
			}
			return nil
		},
	)

	require.Equal(t, []uint64{21, 22}, called)
	require.EqualError(t, err, "failed to redeploy pipeline IDs: 21")
	require.True(t, strings.Contains(output.String(), "total=2 succeeded=1 failed=1"))
}
