package config

import (
	"github.com/urfave/cli/v2"
	"gopkg.in/yaml.v3"
	"io/ioutil"

	"git.icechen.cn/pkg/wujian_develop_tool/util"
)

var DefaultConfigFile = ".drone.yml"

func Init(c *cli.Context) error {
	// 读取配置
	configFileName := c.String("config")
	if configFileName != "" {
		DefaultConfigFile = configFileName
	}
	if err := ReadConfig(); err != nil {
		return err
	}

	appList := c.Args().Slice()
	Config.HasApi = Config.Api.HasApp(appList)
	Config.HasService = Config.Service.HasApp(appList)

	return nil
}

type ConfigFile struct {
	Kind    string      `json:"kind" yaml:"kind"`
	Type    string      `json:"type" yaml:"type"`
	Name    string      `json:"name" yaml:"name"`
	Api     ApiList     `json:"api" yaml:"api"`
	Service ServiceList `json:"service" yaml:"service"`

	HasApi     ApiList     `json:"-" yaml:"-"`
	HasService ServiceList `json:"-" yaml:"-"`
}

type (
	ApiList []Api
	Api     struct {
		Namespace string `json:"namespace" yaml:"namespace"`
		Name      string `json:"name" yaml:"name"`
		AliasName string `json:"alias_name" yaml:"alias_name"`
		Root      string `json:"root" yaml:"root"`
		Type      string `json:"type" yaml:"type"`
		Port      string `json:"port" yaml:"port"`
		Host      string `json:"host,omitempty" yaml:"host,omitempty"`
		Path      string `json:"path,omitempty" yaml:"path,omitempty"`
	}
)

type (
	ServiceList []Service
	Service     struct {
		Namespace string `json:"namespace" yaml:"namespace"`
		Name      string `json:"name" yaml:"name"`
		AliasName string `json:"alias_name" yaml:"alias_name"`
		Root      string `json:"root" yaml:"root"`
		Type      string `json:"type" yaml:"type"`
		Port      string `json:"port" yaml:"port"`
	}
)

var Config ConfigFile

func ReadConfig() error {
	configFile, err := ioutil.ReadFile(DefaultConfigFile)
	if err != nil {
		return err
	}
	err = yaml.Unmarshal(configFile, &Config)
	if err != nil {
		return err
	}
	return nil
}

func (c *ConfigFile) AppendAPI(api Api) error {
	has := false
	for i, a := range c.Api {
		if a.Name == api.Name && a.Namespace == api.Namespace {
			c.Api[i] = api
			has = true
			break
		}
	}

	if !has {
		c.Api = append(c.Api, api)
	}

	out, err := yaml.Marshal(c)
	if err != nil {
		return err
	}

	return util.WriteFileWithNotEdit(DefaultConfigFile, out)
}

func (c *ConfigFile) AppendService(service Service) error {
	has := false
	for i, s := range c.Service {
		if s.Name == service.Name && s.Namespace == service.Namespace {
			c.Service[i] = service
			has = true
			break
		}
	}

	if !has {
		c.Service = append(c.Service, service)
	}

	out, err := yaml.Marshal(c)
	if err != nil {
		return err
	}

	return util.WriteFileWithNotEdit(DefaultConfigFile, out)
}

func (sl ApiList) HasApp(appNameList []string) ApiList {
	if len(appNameList) == 0 {
		return sl
	}

	hasApp := make(ApiList, 0, len(sl))

al:
	for _, api := range sl {
		for _, a := range appNameList {
			if a == api.Name {
				hasApp = append(hasApp, api)
				continue al
			}
		}
	}
	return hasApp
}

func (sl ApiList) GetApp(namespace, appName string) Api {
	for _, api := range sl {
		if api.Name == appName && api.Namespace == namespace {
			return api
		}
	}
	return Api{}
}

func (sl ServiceList) HasApp(appNameList []string) ServiceList {
	if len(appNameList) == 0 {
		return sl
	}

	hasApp := make(ServiceList, 0, len(sl))

sl:
	for _, service := range sl {
		for _, a := range appNameList {
			if a == service.Name {
				hasApp = append(hasApp, service)
				continue sl
			}
		}
	}
	return hasApp
}

func (sl ServiceList) GetApp(namespace, appName string) Service {
	for _, service := range sl {
		if service.Name == appName && service.Namespace == namespace {
			return service
		}
	}
	return Service{}
}