package executor

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/mittwald/goharbor-client/v5/apiv2"
	"github.com/mittwald/goharbor-client/v5/apiv2/model"
)

type HarborOperator struct {
	SourceHarborHost string `json:"sourceHarborHost,omitempty"`

	TargetHarborHost string `json:"targetHarborHost,omitempty"`

	HarborPort string `json:"harborPort,omitempty"`

	HarborAdminUser string `json:"harborAdminUser,omitempty"`

	HarborAdminPass string `json:"harborAdminPass,omitempty"`

	TargetHarborClient *apiv2.RESTClient

	SourceHarborClient *apiv2.RESTClient
}

// NewHarborOperator 返回一个带有默认HarborAdminPass的HarborOperator实例
func NewHarborOperator() *HarborOperator {
	return &HarborOperator{
		HarborPort:      "8033",
		HarborAdminUser: "admin",         // 设置默认值
		HarborAdminPass: "V2ryStr@ngPss", // 设置默认值
	}
}

// HarborOperatorCache 饿汉式单例
var HarborOperatorCache = NewHarborOperator()
var OctopusReplicationPolicyName = "octopus-sync-replication"

func (hOp *HarborOperator) Exec(baseFuncName string, funcArgs ...string) (bool, []string) {
	// 参见 HarborFunctionEnum

	resultOk := true
	var resultLog []string

	switch baseFuncName {
	case "CREATE_PROJECT":
		resultOk, resultLog = hOp.CreateProjectExec(funcArgs)
		break
	case "LIST_PROJECT":
		resultOk, resultLog = hOp.ListProjectExec(funcArgs)
		break
	case "SYNC_PROJECT_BETWEEN_HARBOR":
		resultOk, resultLog = hOp.SyncProjectExec(funcArgs)
		break
	case "SYNC_STATUS_HARBOR":
		resultOk, resultLog = hOp.SyncStatusExec(funcArgs)
		break
	}

	return resultOk, resultLog
}

func (hOp *HarborOperator) CreateProjectExec(funcArgs []string) (bool, []string) {

	if hOp.TargetHarborClient == nil {
		ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], true)
		if !ok {
			return false, []string{
				"[Harbor Create Project] - Error !",
			}
		}
		hOp.TargetHarborClient = createClient
	}
	client := hOp.TargetHarborClient

	// create project
	// 定义你想要创建的仓库（项目）的详细信息

	log.Debug("[Harbor Create Project] - create project !")
	needToCreateProjectNameList := []string{"cmii", "rancher"}
	// 使用客户端创建项目
	ctx := context.Background()
	for _, projectName := range needToCreateProjectNameList {

		log.DebugF("start to create proect => %s", projectName)
		projectReq := &model.ProjectReq{
			ProjectName: projectName, // 仓库名称
			Metadata: &model.ProjectMetadata{
				Public: "true", // 是否是公开的
			},
		}

		exists, _ := client.ProjectExists(ctx, projectName)
		if !exists {

			err := client.NewProject(ctx, projectReq)
			if err != nil {
				errorLog := fmt.Sprintf("Error creating project %s: %s\n", projectName, err.Error())
				return false, []string{errorLog}
			}
		}

		log.DebugF("[Harbor Create Project] - Project %s already exists ! continue ", projectName)

	}

	successLog := "[Harbor CreateProjectExec] - Project Create Success !"
	log.Info(successLog)

	return true, []string{successLog}
}

func (hOp *HarborOperator) CheckAndBuildHarborClient(targetHarborHost string, isTarget bool) (bool, *apiv2.RESTClient) {

	log.InfoF("[Harbor Client Create] - start to create harbor client %s", targetHarborHost)

	parseIP := net.ParseIP(targetHarborHost)
	if parseIP == nil {
		log.Error(
			fmt.Sprintf("[Harbor Client Create] - ip format is wrong! parseIP is =>  %s ", parseIP),
		)
		return false, nil
	}

	if isTarget {
		hOp.TargetHarborHost = "http://" + targetHarborHost + ":" + hOp.HarborPort + "/api/"
		log.DebugF("[Harbor Client Create] - harbor host is => %s", hOp.TargetHarborHost)
	} else {
		hOp.SourceHarborHost = "http://" + targetHarborHost + ":" + hOp.HarborPort + "/api/"
		log.DebugF("[Harbor Client Create] - harbor host is => %s", hOp.SourceHarborHost)
	}

	// check connection
	var client *apiv2.RESTClient
	var err error
	if isTarget {
		client, err = apiv2.NewRESTClientForHost(hOp.TargetHarborHost, hOp.HarborAdminUser, hOp.HarborAdminPass, nil)
	} else {
		client, err = apiv2.NewRESTClientForHost(hOp.SourceHarborHost, hOp.HarborAdminUser, hOp.HarborAdminPass, nil)
	}
	if err != nil {
		errorLog := fmt.Sprintf("Error creating REST client: %s\n", err.Error())
		log.Error(errorLog)
		return false, nil
	}

	return true, client
}

func (hOp *HarborOperator) ListProjectExec(funcArgs []string) (bool, []string) {

	if hOp.TargetHarborClient == nil {
		ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], true)
		if !ok {
			return false, []string{
				"[Harbor Create Project ] - Error !",
			}
		}
		hOp.TargetHarborClient = createClient
	}
	client := hOp.TargetHarborClient

	// 使用客户端列出所有项目
	ctx := context.Background()
	projects, err := client.ListProjects(ctx, "")
	if err != nil {
		fmt.Printf("Error listing projects: %v\n", err)
		os.Exit(1)
	}

	// 打印所有项目的信息
	for _, project := range projects {
		fmt.Printf("Project ID: %d, Name: %s, Public: %v\n", project.ProjectID, project.Name, project.Metadata.Public)
	}

	marshal, _ := json.Marshal(projects)

	return true, []string{
		fmt.Sprintf("List Projects of %s ", hOp.TargetHarborHost),
		string(marshal),
	}
}

func (hOp *HarborOperator) SyncProjectExec(funcArgs []string) (bool, []string) {

	if hOp.TargetHarborClient == nil {
		ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], true)
		if !ok {
			return false, []string{
				"[Harbor Sync Project ] - Error !",
			}
		}
		hOp.TargetHarborClient = createClient
	}
	targetClient := hOp.TargetHarborClient

	if hOp.SourceHarborClient == nil {
		ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[1], false)
		if !ok {
			return false, []string{
				"[Harbor Sync Project ] - Error !",
			}
		}
		hOp.SourceHarborClient = createClient
	}

	needToSynchronizedProject := funcArgs[2]
	log.InfoF("[Harbor Sync Project ] - start to sync harbor project  => %s", needToSynchronizedProject)

	log.DebugF("[Harbor Sync Project ] - start to check projects all exists!")
	ctx := context.Background()

	// check both source and target harbor project exists
	needToCreateProjectNameList := []string{"rancher", "cmii"}

	for _, projectName := range needToCreateProjectNameList {
		syncNotExistHarborProjectError := []string{
			"[Harbor Sync Project ] - project not exists !",
		}
		exists, _ := targetClient.ProjectExists(ctx, projectName)
		if !exists {
			return false, append(syncNotExistHarborProjectError, "targetClient")
		}
	}

	OctopusSourceHarborName := "octopus-source"

	// add source registry to destination harbor
	log.InfoF("[Harbor Sync Project ] - start to create source harbor endpoints => %s", hOp.SourceHarborHost)

	log.Debug("[Harbor Sync Project ] - start to delete exist replication policy !")
	policies, _ := targetClient.ListReplicationPolicies(ctx)
	if policies != nil {
		for _, policy := range policies {
			if policy.Name == OctopusReplicationPolicyName {
				err := targetClient.DeleteReplicationPolicyByID(ctx, policy.ID)
				if err != nil {
					log.ErrorF("[Harbor Sync Project ] - delete exists replication policy failed ! =>  %v ", policy)
				}
			}
		}
	}

	log.Debug("[Harbor Sync Project ] - start to delete exist exist harbor endpoints !")
	exitRegistry, _ := targetClient.GetRegistryByName(ctx, OctopusSourceHarborName)
	if exitRegistry != nil {
		log.Debug("[Harbor Sync Project ] - source endpoints already exists ! delete it !")
		err := targetClient.DeleteRegistryByID(ctx, exitRegistry.ID)
		if err != nil {
			log.ErrorF("[Harbor Sync Project ] -  source endpoints delete failed ! => %v ", exitRegistry)
		}
	}

	// todo cqga failed
	octopusSourceRegistry := &model.Registry{
		Credential: &model.RegistryCredential{
			AccessKey:    "admin",
			AccessSecret: "V2ryStr@ngPss",
			Type:         "basic",
		},
		Insecure: true,
		Name:     OctopusSourceHarborName, // 源 Harbor 实例的注册表 ID，通常为 0
		Type:     "harbor",
		URL:      strings.Split(hOp.SourceHarborHost, "/api")[0],
	}
	err := targetClient.NewRegistry(ctx, octopusSourceRegistry)
	if err != nil {
		sprintf := fmt.Sprintf("[SyncProjectExec] - source endpoints create failed ! => %s", err.Error())
		log.Error(sprintf)
		return false, []string{sprintf}
	}

	// get the real one for it's ID
	realOctopusSourceRegistry, err := targetClient.GetRegistryByName(ctx, OctopusSourceHarborName)
	if err != nil {
		sprintf := fmt.Sprintf("[SyncProjectExec] - get target registry id failed ! => %s", err.Error())
		log.Error(sprintf)
		return false, []string{sprintf}
	}

	// 创建复制策略
	octopusReplicationPolicy := &model.ReplicationPolicy{
		CopyByChunk:               nil,
		Deletion:                  false,
		Description:               "",
		DestNamespace:             "", // 可以指定目标 Harbor 中的特定项目，如果为空，则使用源项目名称
		DestNamespaceReplaceCount: nil,
		SrcRegistry: &model.Registry{
			ID: realOctopusSourceRegistry.ID,
		},
		DestRegistry: &model.Registry{
			ID: 0,
		},
		Enabled: true,
		Filters: []*model.ReplicationFilter{
			{
				Type:  "name",
				Value: needToSynchronizedProject + "/**",
			},
		},
		ID:                0,
		Name:              OctopusReplicationPolicyName,
		Override:          true,
		ReplicateDeletion: false,
		Speed:             nil,
		Trigger: &model.ReplicationTrigger{
			Type: "manual", // 可以是 "manual", "scheduled", 或 "event_based"
			// 如果是 "scheduled"，还需要设置 Cron 表达式
			// TriggerSettings: &model.TriggerSettings{Cron: "0 * * * *"},
		},
	}

	// 在源 Harbor 中创建复制策略
	log.InfoF("[Harbor Sync Project ] - Start To Sync Project => %s !", needToSynchronizedProject)

	err = targetClient.NewReplicationPolicy(ctx, octopusReplicationPolicy.DestRegistry, octopusReplicationPolicy.SrcRegistry, octopusReplicationPolicy.Deletion, octopusReplicationPolicy.Override, octopusReplicationPolicy.Enabled, octopusReplicationPolicy.Filters, octopusReplicationPolicy.Trigger, octopusReplicationPolicy.DestNamespace, octopusReplicationPolicy.Name, octopusReplicationPolicy.Name)

	if err != nil {
		syncErrorMessage := fmt.Sprintf("[Harbor Sync Project ] - Sync Project [ %s ] Failed ! Error is =>  %s\n", needToSynchronizedProject, err.Error())
		log.Error(syncErrorMessage)
		return false, []string{
			syncErrorMessage,
		}
	}

	realOctopusReplicationPolicy, err := targetClient.GetReplicationPolicyByName(ctx, OctopusReplicationPolicyName)
	if err != nil {
		return false, []string{
			"[Harbor Sync Project ] - failed to get the realOctopusReplicationPolicy!",
			err.Error(),
		}
	}

	err = targetClient.TriggerReplicationExecution(ctx, &model.StartReplicationExecution{
		PolicyID: realOctopusReplicationPolicy.ID,
	})
	if err != nil {
		return false, []string{
			"[ Harbor Sync Project ] - failed to start the harbor sync execution !",
			err.Error(),
		}
	}

	return true, []string{
		fmt.Sprintf("[ Harbor Sync Project ] - sync project [ %s ] started !", needToSynchronizedProject),
	}
}

func (hOp *HarborOperator) SyncStatusExec(funcArgs []string) (bool, []string) {

	if hOp.TargetHarborClient == nil {
		ok, createClient := hOp.CheckAndBuildHarborClient(funcArgs[0], true)
		if !ok {
			return false, []string{
				"[ Sync Status ] - Error !",
			}
		}
		hOp.TargetHarborClient = createClient
	}
	targetClient := hOp.TargetHarborClient

	ctx := context.Background()
	// check replication policy exists

	replicationPolicy, err := targetClient.GetReplicationPolicyByName(ctx, OctopusReplicationPolicyName)
	if err != nil {
		return false, []string{
			"[ Sync Status ] - get replication error !",
			err.Error(),
		}
	}

	// list execution status
	replicationExecutions, err := targetClient.ListReplicationExecutions(ctx, &replicationPolicy.ID, nil, nil)
	if err != nil {
		return false, []string{
			"[ Sync Status ] - replication has no sync work !",
			err.Error(),
		}
	}

	// find the newest one  only have one here
	for _, execution := range replicationExecutions {
		if !strings.HasPrefix(execution.Status, "Succeed") {
			bytes, _ := json.Marshal(execution)
			log.InfoF("[sync status]- status are => %v", string(bytes))
			// report status
			return false, []string{
				fmt.Sprintf("[sync status] - not complete !  progress is => %s %%",
					strconv.FormatFloat(float64(execution.Succeed)/float64(execution.Total)*100, 'f', 2, 64)),
			}
		}
	}

	return true, []string{
		"[sync status]- sync completed !",
	}
}

func (hOp *HarborOperator) Command(baseFuncName string, funcArgs ...string) []string {

	return nil
}
