package service

import (
	"context"
	"errors"
	"testing"

	clinic_internal_api "github.com/pingcap-inc/clinic/clinic_data_service/pkg/clinic-internal-api"
	"github.com/pingcap-inc/clinic/clinic_data_service/pkg/dto"
)

type fakeCanonicalClusterDataURLsReader struct {
	target    *clinic_internal_api.ClusterDataURLs
	err       error
	clusterID string
	calls     int
}

func (f *fakeCanonicalClusterDataURLsReader) GetCanonicalClusterDataURLs(_ context.Context, clusterID string) (*clinic_internal_api.ClusterDataURLs, error) {
	f.calls++
	f.clusterID = clusterID
	return f.target, f.err
}

type capturingDataProxyQuerier struct {
	req *dto.DataProxyQueryRequest
}

func (f *capturingDataProxyQuerier) Query(_ context.Context, req *dto.DataProxyQueryRequest) (*dto.DataProxyQueryResult, error) {
	f.req = req
	return &dto.DataProxyQueryResult{}, nil
}

func TestClusterDiffExplicitSlowQueryTargetTakesPrecedence(t *testing.T) {
	reader := &fakeCanonicalClusterDataURLsReader{
		target: &clinic_internal_api.ClusterDataURLs{SlowQueryS3URL: "s3://canonical/slowlogs"},
	}
	service := NewClusterDiffApiService(&capturingDataProxyQuerier{}, reader)

	got, err := service.getSlowQueryDataSourceForCluster(context.Background(), dto.ClusterSideDTO{
		ClusterId: "cluster-1",
		ClusterUrls: dto.ClusterUrls{
			SlowQueryS3URL: "s3://explicit/slowlogs",
		},
	})

	if err != nil {
		t.Fatalf("getSlowQueryDataSourceForCluster returned error: %v", err)
	}
	if got != "s3://explicit/slowlogs" {
		t.Fatalf("data source = %q, want explicit URL", got)
	}
	if reader.calls != 0 {
		t.Fatalf("canonical target reader calls = %d, want 0", reader.calls)
	}
}

func TestClusterDiffUsesCanonicalSlowQueryTarget(t *testing.T) {
	reader := &fakeCanonicalClusterDataURLsReader{
		target: &clinic_internal_api.ClusterDataURLs{SlowQueryS3URL: " s3://canonical-bucket/canonical/slowlogs "},
	}
	querier := &capturingDataProxyQuerier{}
	service := NewClusterDiffApiService(querier, reader)

	_, err := service.querySlowQuery(context.Background(), dto.ClusterSideDTO{
		ClusterId: "cluster-1",
		Provider:  "aws",
		Region:    "ap-southeast-2",
	}, "SELECT 1")

	if err != nil {
		t.Fatalf("querySlowQuery returned error: %v", err)
	}
	if reader.calls != 1 || reader.clusterID != "cluster-1" {
		t.Fatalf("canonical target lookup = calls:%d cluster:%q", reader.calls, reader.clusterID)
	}
	if querier.req == nil {
		t.Fatal("data proxy query was not called")
	}
	if got := querier.req.Options.DataSource; got != "s3://canonical-bucket/canonical/slowlogs" {
		t.Fatalf("data source = %q, want canonical URL", got)
	}
	if got := querier.req.Options.Region; got != "ap-southeast-2" {
		t.Fatalf("region = %q, want physical request region", got)
	}
}

func TestClusterDiffCanonicalSlowQueryTargetFailsClosed(t *testing.T) {
	tests := []struct {
		name   string
		reader *fakeCanonicalClusterDataURLsReader
	}{
		{
			name:   "upstream error",
			reader: &fakeCanonicalClusterDataURLsReader{err: errors.New("unavailable")},
		},
		{
			name:   "nil target",
			reader: &fakeCanonicalClusterDataURLsReader{},
		},
		{
			name:   "empty URL",
			reader: &fakeCanonicalClusterDataURLsReader{target: &clinic_internal_api.ClusterDataURLs{}},
		},
		{
			name:   "unsupported scheme",
			reader: &fakeCanonicalClusterDataURLsReader{target: &clinic_internal_api.ClusterDataURLs{SlowQueryS3URL: "ftp://bucket/slowlogs"}},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service := NewClusterDiffApiService(&capturingDataProxyQuerier{}, tt.reader)
			got, err := service.getSlowQueryDataSourceForCluster(context.Background(), dto.ClusterSideDTO{ClusterId: "cluster-1"})
			if err == nil {
				t.Fatalf("expected error, got data source %q", got)
			}
			if got != "" {
				t.Fatalf("data source = %q, want empty on failure", got)
			}
		})
	}
}
