package framework

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"

	apiresource "github.com/pingcap/test-infra/common/model/resource"
	"github.com/pingcap/test-infra/sdk/resource"
	"github.com/pingcap/test-infra/sdk/resource/impl/k8s"
)

func (f *Framework) CreateMySQL(testbed *k8s.Testbed) *k8s.MySQLNode {
	client := k8s.NewMySQLClient(f.KubeClientSetPack)

	r, err := client.Create([]byte(fmt.Sprintf(`{
    "name": "mysql",
    "testbed": "%s",
    "type": "%s",
    "spec": {
        "image": "docker.io/mysql:8.0.25",
		"port": 3306,
		"resources": {
            "requests": {
                "memory": "1Gi",
                "cpu": "250m",
                "storage": "1Gi"
            }
        },
	    "env": {
			"MYSQL_ALLOW_EMPTY_PASSWORD": "yes",
			"MYSQL_ROOT_HOST":        	  "%%"
	   	},
		"livenessProbe": {
			"exec": {
				"command": ["mysqladmin", "ping"]
			},
			"initialDelaySeconds": 30,
			"periodSeconds": 10,
			"timeoutSeconds": 5
		},
		"readinessProbe": {
			"exec": {
				"command": ["mysql", "-e", "SELECT 1"]
			},
			"initialDelaySeconds": 5,
			"periodSeconds": 2,
			"timeoutSeconds": 1
		}
    }
}
`, testbed.Name, apiresource.ResourceTypeMySQLNode)))

	ExpectNoError(err)
	return r.(*k8s.MySQLNode)
}

func (f *Framework) CreateMySQLWithVolumeMount(testbed *k8s.Testbed, mountPath string) *k8s.MySQLNode {
	client := k8s.NewMySQLClient(f.KubeClientSetPack)

	r, err := client.Create([]byte(fmt.Sprintf(`{
    "name": "mysql",
    "testbed": "%s",
    "type": "%s",
    "spec": {
        "image": "docker.io/mysql:8.0.25",
		"port": 3306,
		"resources": {
            "requests": {
                "memory": "1Gi",
                "cpu": "250m",
                "storage": "1Gi"
            }
        },
		"volumeMount": {
			"mountPath": "%s"
		},
	    "env": {
			"MYSQL_ALLOW_EMPTY_PASSWORD": "yes",
			"MYSQL_ROOT_HOST":        	  "%%"
	   	},
		"livenessProbe": {
			"exec": {
				"command": ["mysqladmin", "ping"]
			},
			"initialDelaySeconds": 30,
			"periodSeconds": 10,
			"timeoutSeconds": 5
		},
		"readinessProbe": {
			"exec": {
				"command": ["mysql", "-e", "SELECT 1"]
			},
			"initialDelaySeconds": 5,
			"periodSeconds": 2,
			"timeoutSeconds": 1
		}
    }
}
`, testbed.Name, apiresource.ResourceTypeMySQLNode, mountPath)))

	ExpectNoError(err)
	return r.(*k8s.MySQLNode)
}

func (f *Framework) GetMySQL(handle apiresource.ResourceHandle) *k8s.MySQLNode {
	client := k8s.NewMySQLClient(f.KubeClientSetPack)
	r, err := client.Get(handle)
	ExpectNoError(err)
	return r.(*k8s.MySQLNode)
}

func (f *Framework) GetMySQLEndpoints(handle apiresource.ResourceHandle) apiresource.ResourceEndpoints {
	client := k8s.NewMySQLClient(f.KubeClientSetPack)
	r, err := client.GetEndpoints(handle)
	ExpectNoError(err)
	return r
}

func (f *Framework) DeleteMySQLWaited(mysql *k8s.MySQLNode) {
	client := k8s.NewMySQLClient(f.KubeClientSetPack)
	ExpectNoError(client.Delete(mysql.ResourceHandle))

	err := wait.PollImmediate(poll, f.DeletionTimeout, func() (done bool, err error) {
		_, err = client.Get(mysql.ResourceHandle)
		if resource.IsResourceNotFoundError(err) {
			return true, nil
		}
		return false, nil
	})
	ExpectNoError(err)
}

func (f *Framework) WaitForMySQLReady(mysql *k8s.MySQLNode, timeout time.Duration, pingCheck bool) error {
	k8s.SetConfig(k8s.Config{
		MySQLCluster: k8s.MySQLClusterConfig{
			ReadyCheck: k8s.MySQLClusterReadyCheckConfig{
				PingDB: pingCheck,
			},
		},
	})

	if err := wait.PollImmediate(poll, timeout, func() (done bool, err error) {
		if err := mysql.Sync(); err != nil {
			return false, err
		}
		return mysql.Ready(), nil
	}); err != nil {
		return fmt.Errorf("wait for mysql ready occur an error: %v", err)
	}
	return nil
}
