package models

import (
	"strings"

	"cloud.o-forge.io/core/oc-lib/models/common/models"
	"cloud.o-forge.io/core/oc-lib/models/resources"
)

type Parameter struct {
	Name  string `yaml:"name,omitempty"`
	Value string `yaml:"value,omitempty"`
}

type Container struct {
	Image        string        `yaml:"image"`
	Command      []string      `yaml:"command,omitempty,flow"`
	Args         []string      `yaml:"args,omitempty,flow"`
	VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty"`
}

func (c *Container) AddVolumeMount(volumeMount VolumeMount, volumes []VolumeMount) []VolumeMount {
	for _, vm := range c.VolumeMounts {
		if vm.Name == volumeMount.Name {
			return volumes
		}
	}
	c.VolumeMounts = append(c.VolumeMounts, volumeMount)
	for _, vm := range c.VolumeMounts {
		for _, v := range volumes {
			if vm.Name == v.Name {
				return volumes
			}
		}
	}
	volumes = append(volumes, volumeMount)
	return volumes
}

type VolumeMount struct {
	Name      string                     `yaml:"name"`
	MountPath string                     `yaml:"mountPath"`
	Storage   *resources.StorageResource `yaml:"-"`
}

type Task struct {
	Name         string   `yaml:"name"`
	Template     string   `yaml:"template"`
	Dependencies []string `yaml:"dependencies,omitempty"`
	Arguments    struct {
		Parameters []Parameter `yaml:"parameters,omitempty"`
	} `yaml:"arguments,omitempty"`
}

type Dag struct {
	Tasks []Task `yaml:"tasks,omitempty"`
}

type TemplateMetadata struct {
	Labels map[string]string `yaml:"labels,omitempty"`
	Annotations map[string]string `yaml:"annotations,omitempty"`
}

type Secret struct {
	Name string `yaml:"name"`
	Key  string `yaml:"key"`
}

type Key struct {
	Key             string  `yaml:"key"`
	Bucket          string  `yaml:"bucket"`
	EndPoint        string  `yaml:"endpoint"`
	Insecure        bool    `yaml:"insecure"`
	AccessKeySecret *Secret `yaml accessKeySecret`
	SecretKeySecret *Secret `yaml secretKeySecret`
}

type Artifact struct {
	Name string `yaml:"name"`
	Path string `yaml:"path"`
	S3   *Key   `yaml:"s3,omitempty"`
}

type InOut struct {
	Parameters []Parameter `yaml:"parameters"`
	Artifacts  []Artifact  `yaml:"artifacts,omitempty"`
}

type Template struct {
	Name      string           `yaml:"name"`
	Inputs    InOut            `yaml:"inputs,omitempty"`
	Outputs   InOut            `yaml:"outputs,omitempty"`
	Container Container        `yaml:"container,omitempty"`
	Dag       *Dag             `yaml:"dag,omitempty"`
	Metadata  TemplateMetadata `yaml:"metadata,omitempty"`
	Resource  ServiceResource  `yaml:"resource,omitempty"`
}

func (template *Template) CreateContainer(processing *resources.ProcessingResource, dag *Dag) {
	instance := processing.GetSelectedInstance()
	if instance == nil {
		return
	}
	inst := instance.(*resources.ProcessingInstance)
	container := Container{Image: inst.Access.Container.Image}
	if container.Image == "" {
		return
	}
	container.Command = []string{"sh", "-c"} // all is bash
	for _, v := range inst.Env {
		template.Inputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name})
	}
	for _, v := range inst.Inputs {
		template.Inputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name})
	}
	for _, v := range inst.Inputs {
		template.Outputs.Parameters = append(template.Inputs.Parameters, Parameter{Name: v.Name})
	}
	cmd := strings.ReplaceAll(inst.Access.Container.Command, container.Image, "")

	for _, a := range strings.Split(cmd, " ") {
		container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
	}
	for _, a := range strings.Split(inst.Access.Container.Args, " ") {
		container.Args = append(container.Args, template.ReplacePerEnv(a, inst.Env))
	}
	container.Args = []string{strings.Join(container.Args, " ")}

	template.Container = container
}

func (template *Template) ReplacePerEnv(arg string, envs []models.Param) string {
	for _, v := range envs {
		if strings.Contains(arg, v.Name) {
			value := "{{ inputs.parameters." + v.Name + " }}"
			arg = strings.ReplaceAll(arg, v.Name, value)
			arg = strings.ReplaceAll(arg, "$"+v.Name, value)
			arg = strings.ReplaceAll(arg, "$", "")
		}
	}
	return arg
}

// Add the metadata that allow Admiralty to pick up an Argo Workflow that needs to be reparted
// The value of "clustername" is the peerId, which must be replaced by the node name's for this specific execution
func (t *Template) AddAdmiraltyAnnotations(peerId string){
	if t.Metadata.Annotations == nil {
		t.Metadata.Annotations = make(map[string]string)
	}
	t.Metadata.Annotations["multicluster.admiralty.io/elect"] = ""
	t.Metadata.Annotations["multicluster.admiralty.io/clustername"] = peerId
}