package cluster

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/pingcap/diag/pkg/models"
	"github.com/pingcap/log"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/db"
)

const ClusterIDFile = "cluster.json"

type ClusterInfo struct {
	DiagVersion  string              `json:"diag_version"`
	ClusterName  string              `json:"cluster_name"`
	RawClusterID json.RawMessage     `json:"cluster_id"`   // the id from pd
	ClusterType  string              `json:"cluster_type"` // tidb-cluster or dm-cluster
	DeployType   string              `json:"deploy_type"`  // deployment type
	Session      string              `json:"session"`
	BeginTime    string              `json:"begin_time"`
	EndTime      string              `json:"end_time"`
	Collectors   []string            `json:"collectors"`
	Topology     *models.TiDBCluster `json:"topology"` // abstract cluster topo

	ClusterID string `json:"-"`
}

func GetClusterToplogy(info *ClusterInfo) db.Topology {
	if info == nil || info.Topology == nil {
		return db.Topology{}
	}

	return db.Topology{
		PD:       len(info.Topology.PD),
		TiDB:     len(info.Topology.TiDB),
		TiKV:     len(info.Topology.TiKV),
		DMMaster: len(info.Topology.DMMaster),
		DMWorker: len(info.Topology.DMWorker),
		TiFlash:  len(info.Topology.TiFlash),
	}
}

func GetClusterVersion(info *ClusterInfo) string {
	if info == nil || info.Topology == nil {
		return ""
	}

	return info.Topology.Version
}

func GetDeployVersion(info *ClusterInfo) string {
	if info == nil || info.Topology == nil {
		return ""
	}

	return info.DeployType
}

func UnmarshalJSON(b []byte) (*ClusterInfo, error) {
	var ci ClusterInfo
	err := json.Unmarshal(b, &ci)
	if err != nil {
		return nil, err
	}

	var clusterIDStr string
	if err = json.Unmarshal(ci.RawClusterID, &clusterIDStr); err != nil {
		var clusterIDInt uint64

		err = json.Unmarshal(ci.RawClusterID, &clusterIDInt)
		if err != nil {
			return nil, err
		}

		if clusterIDInt == 0 {
			clusterIDStr = ""
		} else {
			clusterIDStr = fmt.Sprintf("%d", clusterIDInt)
		}
	}

	ci.ClusterID = clusterIDStr

	return &ci, nil
}

func GetClusterInfoFromDataPath(parentPath string) (*ClusterInfo, error) {
	//tr := tar.NewReader(f)
	//for {
	//	hdr, err := tr.Next()
	//	if err == io.EOF {
	//		break // End of archive
	//	}
	//	if err != nil {
	//		return nil, err
	//	}
	//	if hdr.Name != ClusterIDFile {
	//		continue
	//	}
	//
	//	data, err := io.ReadAll(tr)
	//	if err != nil {
	//		log.Error("read cluster json failed", zap.Error(err))
	//		return nil, err
	//	}
	//
	//	return UnmarshalJSON(data)
	//}
	if !strings.HasSuffix(parentPath, "/") {
		parentPath += "/"
	}
	f, err := os.Open(fmt.Sprintf("%s%s", parentPath, ClusterIDFile))
	if err != nil {
		return nil, err
	}

	data, err := io.ReadAll(f)
	if err != nil {
		log.Error("read cluster json failed", zap.Error(err))
		return nil, err
	}

	return UnmarshalJSON(data)

	// return nil, fmt.Errorf("cluster id file not found in tar file")
}
