package image

import (
	"context"
	"fmt"
	"github.com/mittwald/goharbor-client/v5/apiv2"
	"github.com/mittwald/goharbor-client/v5/apiv2/model"
	"strings"
)

type HarborOperator struct {
	HarborHost   string
	HarborPort   string
	HarborUser   string
	HarborPass   string
	HarborClient *apiv2.RESTClient
}

var LocalHarborOperator = newDefaultInstance

func newDefaultInstance() {

}

const (
	DefaultHarborPort = "8033"
	DefaultHarborUser = "admin"
	DefaultHarborPass = "V2ryStr@ngPss"
)

func (op *HarborOperator) BuildOperator() (bool, error) {
	if op.HarborPort != "" {
		op.HarborHost = op.HarborHost + ":" + op.HarborPort
	}
	if !strings.HasSuffix(op.HarborHost, "/api/") {
		op.HarborHost = op.HarborHost + "/api/"
	}
	log.InfoF("[Harbor Client Create] - start to create harbor client %s", op.HarborHost)

	if op.HarborUser == "" {
		op.HarborUser = DefaultHarborUser
	}
	if op.HarborPass == "" {
		op.HarborPass = DefaultHarborPass
	}

	// check connection

	client, err := apiv2.NewRESTClientForHost(op.HarborHost, op.HarborUser, op.HarborPass, nil)
	if err != nil {
		errorLog := fmt.Sprintf("Error creating REST client: %s\n", err.Error())
		log.Error(errorLog)
		return false, err
	}

	op.HarborClient = client

	return true, nil
}

func (op *HarborOperator) RepoListAll(projectName string) []*model.Repository {

	listRepositories, err := op.HarborClient.ListRepositories(context.TODO(), projectName)
	if err != nil {
		log.ErrorF("RepoListAll error is %s", err.Error())
		return nil
	}
	return listRepositories
}

// RepoAllCmiiImage 返回没有前缀的内容  cmii-uav-user
func (op *HarborOperator) RepoAllCmiiImage() (repoNameList []string) {

	listAll := op.RepoListAll("cmii")
	for _, repository := range listAll {
		prefix := strings.TrimPrefix(repository.Name, "cmii/")
		if strings.HasPrefix(prefix, "cmii") {
			repoNameList = append(repoNameList, prefix)
		}
	}

	// 返回没有
	return repoNameList
}

func (op *HarborOperator) ArtifactListAll(projectName, repoName string) []*model.Artifact {
	listArtifacts, err := op.HarborClient.ListArtifacts(context.TODO(), projectName, repoName)
	if err != nil {
		log.ErrorF("ArtifactListAll error is %s", err.Error())
		return nil
	}
	return listArtifacts
}

func (op *HarborOperator) ArtifactListOne(projectName, repoName, artifactReference string) *model.Artifact {
	artifact, err := op.HarborClient.GetArtifact(context.TODO(), projectName, repoName, artifactReference)
	if err != nil {
		log.ErrorF("ArtifactListOne error is %s", err.Error())
		return nil
	}
	return artifact
}

func (op *HarborOperator) ArtifactDeleteOne(projectName, repoName, artifactReference string) bool {
	err := op.HarborClient.DeleteArtifact(context.TODO(), projectName, repoName, artifactReference)
	if err != nil {
		log.ErrorF("ArtifactDeleteOne error is %s", err.Error())
		return false
	}
	log.InfoF("ArtifactDeleteOne of %s %s %s is success", projectName, repoName, artifactReference)
	return true
}

func (op *HarborOperator) RepoListOne(projectName, repoName string) *model.Repository {

	repository, err := op.HarborClient.GetRepository(context.TODO(), projectName, repoName)
	if err != nil {
		log.ErrorF("RepoListOne error is %s", err.Error())
		return nil
	}

	return repository
}

// CmiiTagFilter 根据tag前缀 找到所有的cmii tag
func (op *HarborOperator) CmiiTagFilter(tagPrefix string) (allCmiiImageList []string) {

	repoNameList := op.RepoAllCmiiImage() // all cmii repo name

	for _, cmiiRepo := range repoNameList {
		// cmii-uav-user
		artifactList := op.ArtifactListAll("cmii", cmiiRepo)
		for _, artifact := range artifactList {
			// list all artifact of cmii-uav-user
			for _, tag := range artifact.Tags {
				if strings.HasPrefix(tag.Name, tagPrefix) {
					// tag has prefix 5.4.0-123  5.4.0-123-123
					allCmiiImageList = append(allCmiiImageList, cmiiRepo+":"+tag.Name)
				}
			}
		}
	}

	return allCmiiImageList
}

func (op *HarborOperator) ArtifactDeleteFromNameTagList(projectName string, nameTagList []string) (errorDeleteList []string) {
	for _, nameTag := range nameTagList {
		split := strings.Split(nameTag, ":")
		if len(split) != 2 {
			log.ErrorF("ArtifactDeleteFromNameTagList error is %s", nameTag)
			errorDeleteList = append(errorDeleteList, nameTag)
			continue
		}

		repoName := split[0]
		tagName := split[1]
		if !op.ArtifactDeleteOne(projectName, repoName, tagName) {
			log.ErrorF("ArtifactDeleteFromNameTagList error is %s %s %s", projectName, repoName, tagName)
			errorDeleteList = append(errorDeleteList, nameTag)
		}
	}

	return errorDeleteList
}
