// Code generated by hand for testing purposes.

package model

import (
	"sort"
	"time"

	"github.com/pingcap-inc/clinic/pkg/db"
	"gorm.io/gorm"
)

// MockHealthCheckRepository is a mock implementation of HealthCheckRepository for testing
type MockHealthCheckRepository struct {
	// Strategy storage
	Strategies map[string]*db.HealthCheckStrategy
	// Result storage
	Results map[string]*db.HealthCheckResult
	// Error to return (optional)
	Error error
	// Call counters used by scanner tests.
	FetchPendingOrRunningHealthCheckJobsBatchCalls int
	CountPendingOrRunningHealthCheckJobsCalls      int
}

// NewMockHealthCheckRepository creates a new mock repository
func NewMockHealthCheckRepository() *MockHealthCheckRepository {
	return &MockHealthCheckRepository{
		Strategies: make(map[string]*db.HealthCheckStrategy),
		Results:    make(map[string]*db.HealthCheckResult),
	}
}

// Strategy operations
func (m *MockHealthCheckRepository) InsertHealthCheckStrategy(strategy *db.HealthCheckStrategy) error {
	if m.Error != nil {
		return m.Error
	}
	m.Strategies[strategy.UUID] = strategy
	return nil
}

func (m *MockHealthCheckRepository) GetHealthCheckStrategyByUUID(uuid string) (*db.HealthCheckStrategy, error) {
	if m.Error != nil {
		return nil, m.Error
	}
	strategy, ok := m.Strategies[uuid]
	if !ok {
		return nil, gorm.ErrRecordNotFound
	}
	return strategy, nil
}

func (m *MockHealthCheckRepository) ListHealthCheckStrategies(clusterID string, dbaasOrgID string, page, perPage int) ([]db.HealthCheckStrategy, int64, error) {
	if m.Error != nil {
		return nil, 0, m.Error
	}
	var result []db.HealthCheckStrategy
	for _, s := range m.Strategies {
		if s.ClusterID == clusterID && s.DbaasOrgID == dbaasOrgID {
			result = append(result, *s)
		}
	}
	total := int64(len(result))

	// Simple pagination
	start := page * perPage
	if start > len(result) {
		start = len(result)
	}
	end := start + perPage
	if end > len(result) {
		end = len(result)
	}

	return result[start:end], total, nil
}

func (m *MockHealthCheckRepository) UpdateHealthCheckStrategy(strategy *db.HealthCheckStrategy) error {
	if m.Error != nil {
		return m.Error
	}
	m.Strategies[strategy.UUID] = strategy
	return nil
}

func (m *MockHealthCheckRepository) DeleteHealthCheckStrategy(uuid string) error {
	if m.Error != nil {
		return m.Error
	}
	delete(m.Strategies, uuid)
	return nil
}

func (m *MockHealthCheckRepository) ListPendingCronHealthCheckStrategies() ([]db.HealthCheckStrategy, error) {
	if m.Error != nil {
		return nil, m.Error
	}
	var result []db.HealthCheckStrategy
	now := time.Now()
	for _, s := range m.Strategies {
		if s.ScheduleType == "cron" && s.Status == "active" && s.NextRunAt != nil && s.NextRunAt.Before(now) {
			result = append(result, *s)
		}
	}
	return result, nil
}

func (m *MockHealthCheckRepository) UpdateHealthCheckStrategyLastRun(uuid string, lastRunAt, nextRunAt *time.Time) error {
	if m.Error != nil {
		return m.Error
	}
	if strategy, ok := m.Strategies[uuid]; ok {
		strategy.LastRunAt = lastRunAt
		strategy.NextRunAt = nextRunAt
	}
	return nil
}

func (m *MockHealthCheckRepository) UpdateHealthCheckStrategyStatus(uuid, status, errorMsg string) error {
	if m.Error != nil {
		return m.Error
	}
	if strategy, ok := m.Strategies[uuid]; ok {
		strategy.Status = status
	}
	return nil
}

// Result operations
func (m *MockHealthCheckRepository) InsertHealthCheckResult(result *db.HealthCheckResult) error {
	if m.Error != nil {
		return m.Error
	}
	m.Results[result.UUID] = result
	return nil
}

func (m *MockHealthCheckRepository) GetHealthCheckResultByUUID(uuid string) (*db.HealthCheckResult, error) {
	if m.Error != nil {
		return nil, m.Error
	}
	result, ok := m.Results[uuid]
	if !ok {
		return nil, gorm.ErrRecordNotFound
	}
	return result, nil
}

func (m *MockHealthCheckRepository) ListHealthCheckResults(clusterID string, dbaasOrgID string, page, perPage int) ([]db.HealthCheckResult, int64, error) {
	if m.Error != nil {
		return nil, 0, m.Error
	}
	var result []db.HealthCheckResult
	for _, r := range m.Results {
		if r.ClusterID == clusterID && r.DbaasOrgID == dbaasOrgID {
			result = append(result, *r)
		}
	}
	total := int64(len(result))

	// Simple pagination
	start := page * perPage
	if start > len(result) {
		start = len(result)
	}
	end := start + perPage
	if end > len(result) {
		end = len(result)
	}

	return result[start:end], total, nil
}

func (m *MockHealthCheckRepository) ListPendingHealthCheckResults() ([]*db.HealthCheckResult, error) {
	if m.Error != nil {
		return nil, m.Error
	}
	return m.pendingOrRunningHealthCheckResults(nil), nil
}

func (m *MockHealthCheckRepository) UpdateHealthCheckResult(result *db.HealthCheckResult) error {
	if m.Error != nil {
		return m.Error
	}
	m.Results[result.UUID] = result
	return nil
}

func (m *MockHealthCheckRepository) UpdateHealthCheckResultStatus(uuid, status, errorMsg string) error {
	if m.Error != nil {
		return m.Error
	}
	if result, ok := m.Results[uuid]; ok {
		result.Status = status
		result.ErrorMsg = errorMsg
	}
	return nil
}

func (m *MockHealthCheckRepository) DeleteHealthCheckResult(uuid string) error {
	if m.Error != nil {
		return m.Error
	}
	delete(m.Results, uuid)
	return nil
}

func (m *MockHealthCheckRepository) FetchPendingOrRunningHealthCheckJobs(results *[]*db.HealthCheckResult) error {
	if m.Error != nil {
		return m.Error
	}
	*results = m.pendingOrRunningHealthCheckResults(nil)
	return nil
}

func (m *MockHealthCheckRepository) FetchPendingOrRunningHealthCheckJobsBatch(results *[]*db.HealthCheckResult, limit int, excludeUUIDs []string) error {
	if m.Error != nil {
		return m.Error
	}
	m.FetchPendingOrRunningHealthCheckJobsBatchCalls++
	if limit <= 0 {
		*results = make([]*db.HealthCheckResult, 0)
		return nil
	}
	pending := m.pendingOrRunningHealthCheckResults(excludeUUIDs)
	if limit > len(pending) {
		limit = len(pending)
	}
	*results = pending[:limit]
	return nil
}

func (m *MockHealthCheckRepository) CountPendingOrRunningHealthCheckJobs(excludeUUIDs []string) (int64, error) {
	if m.Error != nil {
		return 0, m.Error
	}
	m.CountPendingOrRunningHealthCheckJobsCalls++
	return int64(len(m.pendingOrRunningHealthCheckResults(excludeUUIDs))), nil
}

func (m *MockHealthCheckRepository) pendingOrRunningHealthCheckResults(excludeUUIDs []string) []*db.HealthCheckResult {
	excluded := make(map[string]struct{}, len(excludeUUIDs))
	for _, uuid := range excludeUUIDs {
		excluded[uuid] = struct{}{}
	}

	result := make([]*db.HealthCheckResult, 0, len(m.Results))
	for _, r := range m.Results {
		if r == nil {
			continue
		}
		if _, ok := excluded[r.UUID]; ok {
			continue
		}
		if r.Status == string(db.StatusPending) || r.Status == string(db.StatusRunning) || r.Status == string(db.StatusPartial) {
			result = append(result, r)
		}
	}
	sort.Slice(result, func(i, j int) bool {
		if statusRank(result[i].Status) != statusRank(result[j].Status) {
			return statusRank(result[i].Status) < statusRank(result[j].Status)
		}
		if result[i].CreatedAt.Equal(result[j].CreatedAt) {
			return result[i].ID < result[j].ID
		}
		return result[i].CreatedAt.Before(result[j].CreatedAt)
	})
	return result
}

func statusRank(status string) int {
	switch status {
	case string(db.StatusPending):
		return 0
	case string(db.StatusRunning):
		return 1
	case string(db.StatusPartial):
		return 2
	default:
		return 3
	}
}
