package mock

import (
	"context"
	"fmt"
	"time"

	"github.com/ocdp/cluster-service/internal/domain/entity"
	"github.com/ocdp/cluster-service/internal/domain/repository"
)

// HelmClientMock Helm 客户端 Mock 实现
type HelmClientMock struct {
	// Mock 数据存储
	releases  map[string]map[string]*entity.Instance             // clusterID -> releaseName -> instance
	history   map[string]map[string][]*entity.ReleaseHistory     // clusterID -> releaseName -> []history
	estimates map[string]map[string]*repository.ResourceEstimate // clusterID -> releaseName -> estimate
}

// NewHelmClientMock 创建 Mock 实现
func NewHelmClientMock() repository.HelmClient {
	return &HelmClientMock{
		releases:  make(map[string]map[string]*entity.Instance),
		history:   make(map[string]map[string][]*entity.ReleaseHistory),
		estimates: make(map[string]map[string]*repository.ResourceEstimate),
	}
}

func (c *HelmClientMock) SetResourceEstimate(clusterID, namespace, releaseName string, estimate *repository.ResourceEstimate) {
	if c.estimates[clusterID] == nil {
		c.estimates[clusterID] = make(map[string]*repository.ResourceEstimate)
	}
	c.estimates[clusterID][fmt.Sprintf("%s/%s", namespace, releaseName)] = estimate
}

func (c *HelmClientMock) Install(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error {
	// 初始化集群数据
	if c.releases[cluster.ID] == nil {
		c.releases[cluster.ID] = make(map[string]*entity.Instance)
		c.history[cluster.ID] = make(map[string][]*entity.ReleaseHistory)
	}

	// 检查是否已存在
	key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)
	if _, exists := c.releases[cluster.ID][key]; exists {
		return entity.ErrInstanceExists
	}

	// Mock 安装
	instance.Status = entity.StatusDeployed
	instance.Revision = 1
	instance.UpdatedAt = time.Now()

	c.releases[cluster.ID][key] = instance

	// 添加历史记录
	c.history[cluster.ID][key] = []*entity.ReleaseHistory{
		{
			Revision:    1,
			Updated:     time.Now(),
			Status:      entity.StatusDeployed,
			Chart:       fmt.Sprintf("%s-%s", instance.Chart, instance.Version),
			AppVersion:  instance.Version,
			Description: "Install complete",
		},
	}

	return nil
}

func (c *HelmClientMock) Upgrade(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error {
	key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)

	existing, exists := c.releases[cluster.ID][key]
	if !exists {
		return entity.ErrInstanceNotFound
	}

	// Mock 升级
	instance.Revision = existing.Revision + 1
	instance.Status = entity.StatusDeployed
	instance.UpdatedAt = time.Now()

	c.releases[cluster.ID][key] = instance

	// 添加历史记录
	history := &entity.ReleaseHistory{
		Revision:    instance.Revision,
		Updated:     time.Now(),
		Status:      entity.StatusDeployed,
		Chart:       fmt.Sprintf("%s-%s", instance.Chart, instance.Version),
		AppVersion:  instance.Version,
		Description: "Upgrade complete",
	}
	c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history)

	return nil
}

func (c *HelmClientMock) Uninstall(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) error {
	key := fmt.Sprintf("%s/%s", namespace, releaseName)

	if _, exists := c.releases[cluster.ID][key]; !exists {
		return entity.ErrInstanceNotFound
	}

	// Mock 卸载
	delete(c.releases[cluster.ID], key)

	return nil
}

func (c *HelmClientMock) Rollback(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string, revision int) error {
	key := fmt.Sprintf("%s/%s", namespace, releaseName)

	instance, exists := c.releases[cluster.ID][key]
	if !exists {
		return entity.ErrInstanceNotFound
	}

	// 检查历史记录是否存在
	histories := c.history[cluster.ID][key]
	if revision > len(histories) || revision < 1 {
		return fmt.Errorf("revision %d not found", revision)
	}

	// Mock 回滚
	instance.Revision = len(histories) + 1
	instance.Status = entity.StatusDeployed
	instance.UpdatedAt = time.Now()

	c.releases[cluster.ID][key] = instance

	// 添加回滚历史记录
	history := &entity.ReleaseHistory{
		Revision:    instance.Revision,
		Updated:     time.Now(),
		Status:      entity.StatusDeployed,
		Chart:       instance.Chart,
		AppVersion:  instance.Version,
		Description: fmt.Sprintf("Rollback to revision %d", revision),
	}
	c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history)

	return nil
}

func (c *HelmClientMock) GetStatus(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (*entity.Instance, error) {
	key := fmt.Sprintf("%s/%s", namespace, releaseName)

	instance, exists := c.releases[cluster.ID][key]
	if !exists {
		return nil, entity.ErrInstanceNotFound
	}

	return instance, nil
}

func (c *HelmClientMock) GetHistory(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) ([]*entity.ReleaseHistory, error) {
	key := fmt.Sprintf("%s/%s", namespace, releaseName)

	if _, exists := c.releases[cluster.ID][key]; !exists {
		return nil, entity.ErrInstanceNotFound
	}

	histories := c.history[cluster.ID][key]
	if histories == nil {
		return []*entity.ReleaseHistory{}, nil
	}

	return histories, nil
}

func (c *HelmClientMock) List(ctx context.Context, cluster *entity.Cluster, namespace string) ([]*entity.Instance, error) {
	clusterReleases := c.releases[cluster.ID]
	if clusterReleases == nil {
		return []*entity.Instance{}, nil
	}

	instances := make([]*entity.Instance, 0)
	for key, instance := range clusterReleases {
		// 如果指定了 namespace，只返回该 namespace 的
		if namespace != "" && namespace != "all" {
			keyNamespace := instance.Namespace
			if keyNamespace != namespace {
				continue
			}
		}
		instances = append(instances, c.releases[cluster.ID][key])
	}

	return instances, nil
}

func (c *HelmClientMock) GetValues(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (map[string]interface{}, error) {
	key := fmt.Sprintf("%s/%s", namespace, releaseName)

	instance, exists := c.releases[cluster.ID][key]
	if !exists {
		return nil, entity.ErrInstanceNotFound
	}

	return instance.Values, nil
}

func (c *HelmClientMock) GetChartDefaultValues(chartPath string) (map[string]interface{}, error) {
	return map[string]interface{}{
		"replicaCount": 1,
		"image": map[string]interface{}{
			"repository": "nginx",
			"tag":        "latest",
		},
	}, nil
}

func (c *HelmClientMock) EstimateInstanceResources(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) (*repository.ResourceEstimate, error) {
	clusterID := ""
	if cluster != nil {
		clusterID = cluster.ID
	}
	key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)
	if c.estimates[clusterID] != nil {
		if estimate := c.estimates[clusterID][key]; estimate != nil {
			return estimate, nil
		}
	}
	return &repository.ResourceEstimate{}, nil
}
