package healthcheck

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/onsi/gomega"

	apierr "github.com/pingcap-inc/clinic/pkg/api/error"
	"github.com/pingcap-inc/clinic/pkg/auth/session"
	"github.com/pingcap-inc/clinic/pkg/db"
	"github.com/pingcap-inc/clinic/pkg/db/model"
)

// mockRepo is the mock repository for testing
var mockRepo *model.MockHealthCheckRepository

type fakeS3Client struct {
	objects map[string]string
}

type updateErrorHealthCheckRepository struct {
	*model.MockHealthCheckRepository
}

func (r *updateErrorHealthCheckRepository) UpdateHealthCheckResultStatus(uuid, status, errorMsg string) error {
	return fmt.Errorf("update failed")
}

func (f *fakeS3Client) GetObject(input *s3.GetObjectInput) (*s3.GetObjectOutput, error) {
	key := aws.StringValue(input.Key)
	body, ok := f.objects[key]
	if !ok {
		return nil, awserr.New(s3.ErrCodeNoSuchKey, fmt.Sprintf("object not found: %s", key), nil)
	}
	return &s3.GetObjectOutput{Body: io.NopCloser(strings.NewReader(body))}, nil
}

func setupMock() {
	mockRepo = model.NewMockHealthCheckRepository()
}

func setHandler(m string, method func(c *gin.Context), params []gin.Param, body []byte, query string) (int, []byte) {
	w := httptest.NewRecorder()
	context, _ := gin.CreateTestContext(w)
	context.Set(session.CtxUserKey, &session.CtxUser{
		Username:        "test_user_healthcheck",
		UserID:          1,
		Email:           "test_healthcheck",
		Internal:        true,
		OrgIDInApiToken: 1,
	})

	switch m {
	case http.MethodGet:
		context.Request = httptest.NewRequest(http.MethodGet, "/clinic/api/v1/compute-engine/"+query, nil)
		context.Params = params
	case http.MethodPost:
		context.Request = httptest.NewRequest(http.MethodPost, "/clinic/api/v1/compute-engine/", bytes.NewReader(body))
		context.Params = params
		context.Request.Header.Set("Content-Type", "application/json")
	case http.MethodPut:
		context.Request = httptest.NewRequest(http.MethodPut, "/clinic/api/v1/compute-engine/", bytes.NewReader(body))
		context.Params = params
		context.Request.Header.Set("Content-Type", "application/json")
	case http.MethodDelete:
		context.Request = httptest.NewRequest(http.MethodDelete, "/clinic/api/v1/compute-engine/", bytes.NewReader(body))
		context.Params = params
		context.Request.Header.Set("Content-Type", "application/json")
	default:
		panic(fmt.Errorf("unknown http method: %s", m))
	}

	method(context)
	apierr.ErrorHandlerFn(context)
	data := w.Body.String()
	return w.Code, []byte(data)
}

func TestCreateHealthCheckStrategy(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	startTime := time.Now().Add(-24 * time.Hour).Format(time.RFC3339)
	endTime := time.Now().Format(time.RFC3339)

	items := []CheckItem{
		{
			Name:        "Slow Query Check",
			Description: "Check slow queries",
			CheckType:   "sql",
			Params:      `{"topN": 3}`,
			Enabled:     true,
		},
	}

	req := HealthCheckStrategyReq{
		Name:            "Test Health Check Strategy",
		Description:     "Test description",
		ScheduleType:    "manual",
		TimeRangeAStart: startTime,
		TimeRangeAEnd:   endTime,
		Items:           items,
	}

	body, _ := json.Marshal(req)
	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_0"},
	}

	// Create service with mock repository
	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("POST", service.CreateStrategy, params, body, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckStrategyResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.Name).To(gomega.Equal(req.Name))
	g.Expect(resp.UUID).NotTo(gomega.BeEmpty())
	g.Expect(resp.Items).NotTo(gomega.BeEmpty())
}

func TestCheckItemAcceptsObjectParams(t *testing.T) {
	g := gomega.NewWithT(t)

	var item CheckItem
	err := json.Unmarshal([]byte(`{
		"name": "sql_tikv_high_duration",
		"description": "SQL TiKV High Duration",
		"checkType": "sql",
		"params": {
			"duration_threshold_ms": 1000,
			"topsql_top_n": 5
		},
		"enabled": true
	}`), &item)

	g.Expect(err).To(gomega.Succeed())
	g.Expect(item.Name).To(gomega.Equal("sql_tikv_high_duration"))
	g.Expect(item.Params).To(gomega.Equal(`{"duration_threshold_ms":1000,"topsql_top_n":5}`))
}

func TestListHealthCheckStrategies(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Add mock data
	strategy := &db.HealthCheckStrategy{
		UUID:         uuid.NewString(),
		ClusterID:    "HealthCheck_Test_Cluster_1",
		DbaasOrgID:   "1",
		CreatorID:    1,
		Name:         "List Test Strategy",
		Description:  "For list test",
		ScheduleType: "manual",
		Status:       "active",
	}
	mockRepo.Strategies[strategy.UUID] = strategy

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_1"},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("GET", service.ListStrategies, params, nil, "?page=0&limit=10")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp ListHealthCheckStrategyResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.Total).To(gomega.BeNumerically(">=", 1))
}

func TestGetHealthCheckStrategy(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock strategy
	strategyUUID := uuid.NewString()
	items := []CheckItem{
		{
			Name:        "Test Item",
			Description: "For get test",
			CheckType:   "metrics",
			Enabled:     true,
		},
	}
	itemsJSON, _ := json.Marshal(items)

	strategy := &db.HealthCheckStrategy{
		UUID:         strategyUUID,
		ClusterID:    "HealthCheck_Test_Cluster_2",
		DbaasOrgID:   "1",
		CreatorID:    1,
		Name:         "Get Test Strategy",
		Description:  "For get test",
		ScheduleType: "manual",
		Status:       "active",
		Items:        string(itemsJSON),
	}
	mockRepo.Strategies[strategyUUID] = strategy

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_2"},
		{Key: "uuid", Value: strategyUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("GET", service.GetStrategy, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckStrategyResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.UUID).To(gomega.Equal(strategyUUID))
	g.Expect(resp.Name).To(gomega.Equal(strategy.Name))
}

func TestUpdateHealthCheckStrategy(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock strategy
	strategyUUID := uuid.NewString()
	strategy := &db.HealthCheckStrategy{
		UUID:         strategyUUID,
		ClusterID:    "HealthCheck_Test_Cluster_0",
		DbaasOrgID:   "1",
		CreatorID:    1,
		Name:         "Original Name",
		Description:  "Original description",
		ScheduleType: "manual",
		Status:       "active",
	}
	mockRepo.Strategies[strategyUUID] = strategy

	// Update the strategy
	updateReq := HealthCheckStrategyReq{
		Name:        "Updated Name",
		Description: "Updated description",
	}
	body, _ := json.Marshal(updateReq)

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_0"},
		{Key: "uuid", Value: strategyUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("PUT", service.UpdateStrategy, params, body, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckStrategyResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.Name).To(gomega.Equal(updateReq.Name))
	g.Expect(resp.Description).To(gomega.Equal(updateReq.Description))
}

func TestDeleteHealthCheckStrategy(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock strategy
	strategyUUID := uuid.NewString()
	strategy := &db.HealthCheckStrategy{
		UUID:         strategyUUID,
		ClusterID:    "HealthCheck_Test_Cluster_1",
		DbaasOrgID:   "1",
		CreatorID:    1,
		Name:         "Delete Test Strategy",
		Description:  "For delete test",
		ScheduleType: "manual",
		Status:       "active",
	}
	mockRepo.Strategies[strategyUUID] = strategy

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_1"},
		{Key: "uuid", Value: strategyUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, _ := setHandler("DELETE", service.DeleteStrategy, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	// Verify deletion
	_, exists := mockRepo.Strategies[strategyUUID]
	g.Expect(exists).To(gomega.BeFalse())
}

func TestTriggerHealthCheck(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock strategy with items
	strategyUUID := uuid.NewString()
	startTime := time.Now().Add(-24 * time.Hour)
	endTime := time.Now()
	startTimeStr := startTime.Format(time.RFC3339)
	endTimeStr := endTime.Format(time.RFC3339)

	items := []CheckItem{
		{
			Name:        "Slow Query Check",
			Description: "Check slow queries",
			CheckType:   "sql",
			Enabled:     true,
		},
		{
			Name:        "Disabled Check",
			Description: "Disabled item",
			CheckType:   "metrics",
			Enabled:     false,
		},
	}
	itemsJSON, _ := json.Marshal(items)

	strategy := &db.HealthCheckStrategy{
		UUID:                strategyUUID,
		ClusterID:           "HealthCheck_Test_Cluster_0",
		DbaasOrgID:          "1",
		CreatorID:           1,
		Name:                "Trigger Test Strategy",
		Description:         "For trigger test",
		ScheduleType:        "manual",
		Status:              "active",
		Items:               string(itemsJSON),
		TimeRangeAStartExpr: startTimeStr,
		TimeRangeAEndExpr:   endTimeStr,
	}
	mockRepo.Strategies[strategyUUID] = strategy

	triggerReq := TriggerHealthCheckReq{
		TimeRangeAStart: startTimeStr,
		TimeRangeAEnd:   endTimeStr,
	}
	body, _ := json.Marshal(triggerReq)

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_0"},
		{Key: "uuid", Value: strategyUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("POST", service.TriggerCheck, params, body, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckTaskResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	// Should return the result UUID
	g.Expect(resp.ResultUUID).NotTo(gomega.BeEmpty())
}

func TestSlowLogTopDigestCreateTriggerAndGetResult(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	clusterID := "HealthCheck_Test_Cluster_TopDigest"
	startTime := "2026-04-21T00:00:00Z"
	endTime := "2026-04-21T01:00:00Z"
	items := []CheckItem{
		{
			Name:        "tablefullscan_slow_query",
			Description: "Existing TableFullScan item",
			CheckType:   "sql",
			Enabled:     true,
		},
		{
			Name:        "slowlog_top_digest",
			Description: "Slow Log Top Digest",
			CheckType:   "sql",
			Params:      `{"dimensions":["count","total_keys"],"topN":2}`,
			Enabled:     true,
		},
	}
	req := HealthCheckStrategyReq{
		Name:            "Slow Log Top Digest Strategy",
		Description:     "Full API chain test",
		ScheduleType:    "manual",
		TimeRangeAStart: startTime,
		TimeRangeAEnd:   endTime,
		Items:           items,
	}
	body, _ := json.Marshal(req)
	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)
	status, respBody := setHandler(http.MethodPost, service.CreateStrategy, params, body, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var createResp HealthCheckStrategyResp
	g.Expect(json.Unmarshal(respBody, &createResp)).To(gomega.Succeed())
	g.Expect(createResp.Items).To(gomega.HaveLen(2))
	g.Expect(createResp.Items[1].Name).To(gomega.Equal("slowlog_top_digest"))
	g.Expect(createResp.Items[1].Params).To(gomega.Equal(`{"dimensions":["count","total_keys"],"topN":2}`))

	triggerReq := TriggerHealthCheckReq{
		ItemNames:       []string{"slowlog_top_digest"},
		TimeRangeAStart: startTime,
		TimeRangeAEnd:   endTime,
	}
	triggerBody, _ := json.Marshal(triggerReq)
	triggerParams := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: createResp.UUID},
	}
	status, respBody = setHandler(http.MethodPost, service.TriggerCheck, triggerParams, triggerBody, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var triggerResp HealthCheckTaskResp
	g.Expect(json.Unmarshal(respBody, &triggerResp)).To(gomega.Succeed())
	g.Expect(triggerResp.ResultUUID).NotTo(gomega.BeEmpty())

	result := mockRepo.Results[triggerResp.ResultUUID]
	g.Expect(result).NotTo(gomega.BeNil())
	var itemsToRun []CheckItem
	g.Expect(json.Unmarshal([]byte(result.ItemsToRun), &itemsToRun)).To(gomega.Succeed())
	g.Expect(itemsToRun).To(gomega.HaveLen(1))
	g.Expect(itemsToRun[0].Name).To(gomega.Equal("slowlog_top_digest"))
	g.Expect(itemsToRun[0].Params).To(gomega.Equal(`{"dimensions":["count","total_keys"],"topN":2}`))

	result.Status = string(db.StatusSuccess)
	s3Key := fmt.Sprintf("%s/%s_%s_slowlog_top_digest.json", healthCheckReportPrefix, clusterID, result.UUID)
	service.s3Client = &fakeS3Client{objects: map[string]string{
		s3Key: `{"name":"slowlog_top_digest","status":"success","results":{"top_by_count":[{"digest":"digest-a","slow_count":2}]}}`,
	}}

	getParams := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: result.UUID},
	}
	status, respBody = setHandler(http.MethodGet, service.GetResult, getParams, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var report HealthCheckCombinedReport
	g.Expect(json.Unmarshal(respBody, &report)).To(gomega.Succeed())
	g.Expect(report.Status).To(gomega.Equal(string(db.StatusSuccess)))
	g.Expect(report.Items).To(gomega.HaveLen(1))
	g.Expect(report.Items[0].Name).To(gomega.Equal("slowlog_top_digest"))
	g.Expect(report.Items[0].Status).To(gomega.Equal("success"))
	g.Expect(report.Items[0].CheckType).To(gomega.Equal("sql"))

	var itemParams map[string]any
	g.Expect(json.Unmarshal(report.Items[0].Params, &itemParams)).To(gomega.Succeed())
	g.Expect(itemParams["topN"]).To(gomega.Equal(float64(2)))

	var content map[string]any
	g.Expect(json.Unmarshal(report.Items[0].Content, &content)).To(gomega.Succeed())
	g.Expect(content["name"]).To(gomega.Equal("slowlog_top_digest"))
	g.Expect(content["results"]).NotTo(gomega.BeNil())
}

func TestListHealthCheckResults(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock result
	resultUUID := uuid.NewString()
	result := &db.HealthCheckResult{
		UUID:         resultUUID,
		StrategyUUID: uuid.NewString(),
		ClusterID:    "HealthCheck_Test_Cluster_2",
		DbaasOrgID:   "1",
		ItemsToRun:   `["Test Item"]`,
		Status:       string(db.StatusSuccess),
	}
	mockRepo.Results[resultUUID] = result

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_2"},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, respBody := setHandler("GET", service.ListResults, params, nil, "?page=0&limit=10")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp ListHealthCheckResultResp
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.Total).To(gomega.BeNumerically(">=", 1))
}

func TestGetHealthCheckResultNotReady(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock strategy
	strategyUUID := uuid.NewString()
	strategy := &db.HealthCheckStrategy{
		UUID:         strategyUUID,
		ClusterID:    "HealthCheck_Test_Cluster_0",
		DbaasOrgID:   "1",
		CreatorID:    1,
		Name:         "Test Strategy",
		Items:        `[{"name":"Test Item","checkType":"sql","enabled":true}]`,
		ScheduleType: "manual",
		Status:       "active",
	}
	mockRepo.Strategies[strategyUUID] = strategy

	// Create a pending result (not ready)
	resultUUID := uuid.NewString()
	result := &db.HealthCheckResult{
		UUID:         resultUUID,
		StrategyUUID: strategyUUID,
		ClusterID:    "HealthCheck_Test_Cluster_0",
		DbaasOrgID:   "1",
		ItemsToRun:   `["Test Item"]`,
		Status:       string(db.StatusPending),
	}
	mockRepo.Results[resultUUID] = result

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_0"},
		{Key: "uuid", Value: resultUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	// GetResult now returns combined report with item statuses
	status, respBody := setHandler("GET", service.GetResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckCombinedReport
	err := json.Unmarshal(respBody, &resp)
	g.Expect(err).To(gomega.Succeed())
	g.Expect(resp.Status).To(gomega.Equal(string(db.StatusPending)))
	g.Expect(len(resp.Items)).To(gomega.Equal(1))
	g.Expect(resp.Items[0].Status).To(gomega.Equal("pending"))
}

func TestGetHealthCheckResultReadRepairsPartialToSuccess(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	clusterID := "HealthCheck_ReadRepair_Cluster"
	resultUUID := uuid.NewString()
	items := []CheckItem{
		{Name: "metrics_healthcheck", CheckType: "metrics", Enabled: true},
		{Name: "config_check", CheckType: "config", Enabled: true},
	}
	itemsJSON, _ := json.Marshal(items)
	result := &db.HealthCheckResult{
		UUID:       resultUUID,
		ClusterID:  clusterID,
		DbaasOrgID: "1",
		ItemsToRun: string(itemsJSON),
		Status:     string(db.StatusPartial),
	}
	mockRepo.Results[resultUUID] = result

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)
	service.s3Client = &fakeS3Client{objects: map[string]string{
		fmt.Sprintf("%s/%s_%s_metrics_healthcheck.json", healthCheckReportPrefix, clusterID, resultUUID): `{"name":"metrics_healthcheck","status":"success"}`,
		fmt.Sprintf("%s/%s_%s_config_check.json", healthCheckReportPrefix, clusterID, resultUUID):        `{"name":"config_check","status":"success"}`,
	}}

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: resultUUID},
	}
	status, respBody := setHandler(http.MethodGet, service.GetResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckCombinedReport
	g.Expect(json.Unmarshal(respBody, &resp)).To(gomega.Succeed())
	g.Expect(resp.Status).To(gomega.Equal(string(db.StatusSuccess)))
	g.Expect(resp.Items).To(gomega.HaveLen(2))
	g.Expect(resp.Items[0].Status).To(gomega.Equal("success"))
	g.Expect(resp.Items[1].Status).To(gomega.Equal("success"))
	g.Expect(mockRepo.Results[resultUUID].Status).To(gomega.Equal(string(db.StatusSuccess)))
}

func TestListHealthCheckResultsReadRepairsPartialToSuccess(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	clusterID := "HealthCheck_List_ReadRepair_Cluster"
	resultUUID := uuid.NewString()
	items := []CheckItem{
		{Name: "metrics_healthcheck", CheckType: "metrics", Enabled: true},
		{Name: "config_check", CheckType: "config", Enabled: true},
	}
	itemsJSON, _ := json.Marshal(items)
	result := &db.HealthCheckResult{
		UUID:       resultUUID,
		ClusterID:  clusterID,
		DbaasOrgID: "1",
		ItemsToRun: string(itemsJSON),
		Status:     string(db.StatusPartial),
	}
	mockRepo.Results[resultUUID] = result

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)
	service.s3Client = &fakeS3Client{objects: map[string]string{
		fmt.Sprintf("%s/%s_%s_metrics_healthcheck.json", healthCheckReportPrefix, clusterID, resultUUID): `{"name":"metrics_healthcheck","status":"success"}`,
		fmt.Sprintf("%s/%s_%s_config_check.json", healthCheckReportPrefix, clusterID, resultUUID):        `{"name":"config_check","status":"success"}`,
	}}

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
	}
	status, respBody := setHandler(http.MethodGet, service.ListResults, params, nil, "?page=0&limit=10")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp ListHealthCheckResultResp
	g.Expect(json.Unmarshal(respBody, &resp)).To(gomega.Succeed())
	g.Expect(resp.Results).To(gomega.HaveLen(1))
	g.Expect(resp.Results[0].Status).To(gomega.Equal(string(db.StatusSuccess)))
	g.Expect(mockRepo.Results[resultUUID].Status).To(gomega.Equal(string(db.StatusSuccess)))
}

func TestGetHealthCheckResultUsesS3FailedStatus(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	clusterID := "HealthCheck_Failed_Item_Cluster"
	resultUUID := uuid.NewString()
	items := []CheckItem{
		{Name: "metrics_healthcheck", CheckType: "metrics", Enabled: true},
		{Name: "config_check", CheckType: "config", Enabled: true},
	}
	itemsJSON, _ := json.Marshal(items)
	result := &db.HealthCheckResult{
		UUID:       resultUUID,
		ClusterID:  clusterID,
		DbaasOrgID: "1",
		ItemsToRun: string(itemsJSON),
		Status:     string(db.StatusPartial),
	}
	mockRepo.Results[resultUUID] = result

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)
	service.s3Client = &fakeS3Client{objects: map[string]string{
		fmt.Sprintf("%s/%s_%s_metrics_healthcheck.json", healthCheckReportPrefix, clusterID, resultUUID): `{"name":"metrics_healthcheck","status":"success"}`,
		fmt.Sprintf("%s/%s_%s_config_check.json", healthCheckReportPrefix, clusterID, resultUUID):        `{"name":"config_check","status":"failed","errorMsg":"config query failed"}`,
	}}

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: resultUUID},
	}
	status, respBody := setHandler(http.MethodGet, service.GetResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckCombinedReport
	g.Expect(json.Unmarshal(respBody, &resp)).To(gomega.Succeed())
	g.Expect(resp.Status).To(gomega.Equal(string(db.StatusPartialFailed)))
	g.Expect(resp.Items[1].Status).To(gomega.Equal("failed"))
	g.Expect(resp.Items[1].ErrorMsg).To(gomega.Equal("config query failed"))
	g.Expect(mockRepo.Results[resultUUID].Status).To(gomega.Equal(string(db.StatusPartialFailed)))
}

func TestGetHealthCheckResultStaysPartialWhenS3Missing(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	clusterID := "HealthCheck_Missing_Item_Cluster"
	resultUUID := uuid.NewString()
	items := []CheckItem{
		{Name: "metrics_healthcheck", CheckType: "metrics", Enabled: true},
		{Name: "config_check", CheckType: "config", Enabled: true},
	}
	itemsJSON, _ := json.Marshal(items)
	result := &db.HealthCheckResult{
		UUID:       resultUUID,
		ClusterID:  clusterID,
		DbaasOrgID: "1",
		ItemsToRun: string(itemsJSON),
		Status:     string(db.StatusPartial),
	}
	mockRepo.Results[resultUUID] = result

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)
	service.s3Client = &fakeS3Client{objects: map[string]string{
		fmt.Sprintf("%s/%s_%s_metrics_healthcheck.json", healthCheckReportPrefix, clusterID, resultUUID): `{"name":"metrics_healthcheck","status":"success"}`,
	}}

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: resultUUID},
	}
	status, respBody := setHandler(http.MethodGet, service.GetResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckCombinedReport
	g.Expect(json.Unmarshal(respBody, &resp)).To(gomega.Succeed())
	g.Expect(resp.Status).To(gomega.Equal(string(db.StatusPartial)))
	g.Expect(resp.Items[0].Status).To(gomega.Equal("success"))
	g.Expect(resp.Items[1].Status).To(gomega.Equal("pending"))
	g.Expect(mockRepo.Results[resultUUID].Status).To(gomega.Equal(string(db.StatusPartial)))
}

func TestGetHealthCheckResultReturnsComputedStatusWhenReadRepairFails(t *testing.T) {
	g := gomega.NewWithT(t)
	baseRepo := model.NewMockHealthCheckRepository()

	clusterID := "HealthCheck_ReadRepair_Update_Fail_Cluster"
	resultUUID := uuid.NewString()
	items := []CheckItem{
		{Name: "metrics_healthcheck", CheckType: "metrics", Enabled: true},
	}
	itemsJSON, _ := json.Marshal(items)
	result := &db.HealthCheckResult{
		UUID:       resultUUID,
		ClusterID:  clusterID,
		DbaasOrgID: "1",
		ItemsToRun: string(itemsJSON),
		Status:     string(db.StatusPartial),
	}
	baseRepo.Results[resultUUID] = result

	service := NewHealthCheckServiceWithRepository(nil, nil, &updateErrorHealthCheckRepository{baseRepo})
	service.s3Client = &fakeS3Client{objects: map[string]string{
		fmt.Sprintf("%s/%s_%s_metrics_healthcheck.json", healthCheckReportPrefix, clusterID, resultUUID): `{"name":"metrics_healthcheck","status":"success"}`,
	}}

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: clusterID},
		{Key: "uuid", Value: resultUUID},
	}
	status, respBody := setHandler(http.MethodGet, service.GetResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	var resp HealthCheckCombinedReport
	g.Expect(json.Unmarshal(respBody, &resp)).To(gomega.Succeed())
	g.Expect(resp.Status).To(gomega.Equal(string(db.StatusSuccess)))
	g.Expect(baseRepo.Results[resultUUID].Status).To(gomega.Equal(string(db.StatusPartial)))
}

func TestDeleteHealthCheckResult(t *testing.T) {
	g := gomega.NewWithT(t)
	setupMock()

	// Create mock result
	resultUUID := uuid.NewString()
	result := &db.HealthCheckResult{
		UUID:         resultUUID,
		StrategyUUID: uuid.NewString(),
		ClusterID:    "HealthCheck_Test_Cluster_1",
		DbaasOrgID:   "1",
		ItemsToRun:   `["Test Item"]`,
		Status:       string(db.StatusSuccess),
	}
	mockRepo.Results[resultUUID] = result

	params := []gin.Param{
		{Key: "oid", Value: "1"},
		{Key: "cid", Value: "HealthCheck_Test_Cluster_1"},
		{Key: "uuid", Value: resultUUID},
	}

	service := NewHealthCheckServiceWithRepository(nil, nil, mockRepo)

	status, _ := setHandler("DELETE", service.DeleteResult, params, nil, "")
	g.Expect(status).To(gomega.Equal(http.StatusOK))

	// Verify deletion
	_, exists := mockRepo.Results[resultUUID]
	g.Expect(exists).To(gomega.BeFalse())
}
