package config

import (
	"fmt"
	"os"

	"helm.sh/helm/v3/pkg/chart"
	"helm.sh/helm/v3/pkg/chart/loader"
	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/yaml"

	"github.com/tidbcloud/infra-provider/pkg/config"
	"github.com/tidbcloud/infra-provider/pkg/helm"
)

type ChaosConfig struct {
	Region string `json:"region"`
	ChaosServerConfig
	Predicate metav1.LabelSelector `json:"predicate"`
}

type ChaosServerConfig struct {
	ChaosMesh ChaosMeshConfig `json:"chaosMesh"`
}

type ChaosMeshConfig struct {
	config.HelmConfig `json:",inline"`
	ControllerManager ControllerManagerConfig `json:"controllerManager"`
	ChaosDaemon       ChaosDaemonConfig       `json:"chaosDaemon"`
}

type ControllerManagerConfig struct {
	Image config.ImageConfig `json:"image"`
}

type ChaosDaemonConfig struct {
	Image config.ImageConfig `json:"image"`
}

const (
	chaosMeshNamespace   = "chaos-mesh"
	chaosMeshReleaseName = "chaos-mesh"
)

func (c *ChaosMeshConfig) GetNamespace() string {
	return chaosMeshNamespace
}

func (c *ChaosMeshConfig) GetName() string {
	return chaosMeshReleaseName
}

func (c *ChaosMeshConfig) ToHelmValues() map[string]interface{} {
	// TODO: merge configOverride
	return map[string]interface{}{
		"controllerManager": map[string]interface{}{
			"replicaCount":            1,
			"allowHostNetworkTesting": true,
			"image": map[string]interface{}{
				"registry":   c.ControllerManager.Image.Repo,
				"repository": c.ControllerManager.Image.Name,
				"tag":        c.ControllerManager.Image.Tag,
			},
			"resources": map[string]interface{}{
				"requests": map[string]interface{}{
					"cpu":    "100m",
					"memory": "100Mi",
				},
				"limits": map[string]interface{}{
					"cpu":    2,
					"memory": "2Gi",
				},
			},
			"env": map[string]interface{}{
				"WEBHOOK_PORT": 443,
			},
		},
		"chaosDaemon": map[string]interface{}{
			"image": map[string]interface{}{
				"registry":   c.ChaosDaemon.Image.Repo,
				"repository": c.ChaosDaemon.Image.Name,
				"tag":        c.ChaosDaemon.Image.Tag,
			},
			"resources": map[string]interface{}{
				"requests": map[string]interface{}{
					"cpu":    "10m",
					"memory": "10Mi",
				},
				"limits": map[string]interface{}{
					"cpu":    "500m",
					"memory": "500Mi",
				},
			},
			"tolerations": []map[string]interface{}{
				{
					"operator": "Exists",
				},
			},
		},
		"dashboard": map[string]interface{}{
			// disable chaos-dashboard component
			"create": false,
		},
	}
}

func (c *ChaosMeshConfig) ToHelmChart() (result *chart.Chart, err error) {
	result, err = loader.Load(c.ChartPath)
	if err != nil {
		return nil, fmt.Errorf("failed to load helm chart %q: %w", c.ChartPath, err)
	}
	return
}

func (c *ChaosMeshConfig) GetCRDs() ([]*apiextensionsv1.CustomResourceDefinition, error) {
	var result []*apiextensionsv1.CustomResourceDefinition
	for _, path := range c.CRDPaths {
		crd, err := helm.LoadCRD(path)
		if err != nil {
			return nil, err
		}
		result = append(result, crd...)
	}
	return result, nil
}

func LoadChaosConfig(path string) (ChaosConfig, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return ChaosConfig{}, err
	}

	var config ChaosConfig
	err = yaml.Unmarshal(data, &config)
	if err != nil {
		return ChaosConfig{}, err
	}

	return config, nil
}
