package main

import (
	"flag"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/shopspring/decimal"
	"gopkg.in/yaml.v2"
)

const (
	tierUnitFilenamePrefix = "tier_unit"
)

var (
	yamlDir string
	outDir  string
)

func main() {
	flag.StringVar(&yamlDir, "yamlDir", ".", "directory of tiers")
	flag.StringVar(&outDir, "outDir", ".", "directory of outputs")
	flag.Parse()

	fs, err := os.ReadDir(yamlDir)
	if err != nil {
		panic(err)
	}
	var data []byte
	for _, f := range fs {
		if strings.HasSuffix(f.Name(), ".yaml") && strings.HasPrefix(f.Name(), tierUnitFilenamePrefix) {
			b, err := os.ReadFile(path.Join(yamlDir, f.Name()))
			if err != nil {
				panic(err)
			}
			data = append(data, b...)
			data = append(data, []byte("\r\n")...)
		}
	}

	var nodes []*tierUnitYaml
	err = yaml.Unmarshal(data, &nodes)
	if err != nil {
		panic(err)
	}

	node2Sku(nodes)
}

func node2Sku(nodes []*tierUnitYaml) {

	var skus []SKU
	exists := make(map[string]bool)
	for _, node := range nodes {
		// skip azure
		if node.CloudProvider == "azure" {
			continue
		}
		for _, region := range node.Regions {
			skuNode := node.ToInstanceSKU(node.CloudProvider, region)
			if !exists[skuNode.hashcode()] {
				exists[skuNode.hashcode()] = true
				skus = append(skus, skuNode)
			}
			if node.Storage != nil {
				diskSkus := node.ToStorageSKUs(node.CloudProvider, region)
				for _, sku := range diskSkus {
					if !exists[sku.hashcode()] {
						exists[sku.hashcode()] = true
						skus = append(skus, sku)
					}
				}
			}
		}
	}

	skuFile, err := os.Create(path.Join(outDir, "sku-node.yaml"))
	if err != nil {
		panic(err)
	}
	defer skuFile.Close()
	o, err := yaml.Marshal(skus)
	if err != nil {
		panic(err)
	}
	_, err = skuFile.Write(o)
	if err != nil {
		panic(err)
	}
}

type SKU struct {
	Provider       string          `yaml:"provider"`
	Region         string          `yaml:"region"`
	ResourceType   string          `yaml:"resourceType"`
	Price          decimal.Decimal `yaml:"price"`
	ResourceDetail ResourceDetail  `yaml:"resourceDetail"`
	MultipleFactor *MultipleFactor `yaml:"multipleFactor,omitempty"`
	Category       string          `yaml:"category"` // node type 和 category有啥区别
	Description    string          `yaml:"description"`
}

func (s SKU) hashcode() string {
	hash := s.Provider + s.Region + s.ResourceType + s.Price.String() + s.ResourceDetail.InstanceType + s.ResourceDetail.DiskType +
		s.ResourceDetail.Topology
	if s.MultipleFactor != nil {
		hash += s.MultipleFactor.hashcode()
	}
	return hash
}

type ResourceDetail struct {
	InstanceType string `yaml:"instanceType,omitempty"`
	DiskType     string `yaml:"diskType,omitempty"`
	Topology     string `yaml:"topology,omitempty"`
}

type MultipleFactor struct {
	Label     string `yaml:"label"`
	Threshold int    `yaml:"threshold"`
}

func (mf *MultipleFactor) hashcode() string {
	return mf.Label + fmt.Sprint(mf.Threshold)
}
