package transform

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/project"
)

func TransformComposeFile(composeFile string, projectName string) (ecs.TaskDefinition, error) {
	task := ecs.TaskDefinition{
		ContainerDefinitions: []*ecs.ContainerDefinition{},
		Volumes:              []*ecs.Volume{},
	}

	project, err := docker.NewProject(&docker.Context{
		Context: project.Context{
			ComposeFile: composeFile,
			ProjectName: projectName,
		}})
	if err != nil {
		return task, err
	}

	for name, config := range project.Configs {
		var def = ecs.ContainerDefinition{}

		if config.Name != "" {
			def.Name = aws.String(config.Name)
		}

		if config.Image != "" {
			def.Image = aws.String(config.Image)
		}

		if config.Hostname != "" {
			def.Hostname = aws.String(config.Hostname)
		}

		if config.WorkingDir != "" {
			def.WorkingDirectory = aws.String(config.WorkingDir)
		}

		if config.CPUShares > 0 {
			def.Cpu = aws.Int64(config.CPUShares)
		}

		if config.MemLimit > 0 {
			def.Memory = aws.Int64(config.MemLimit)
		}

		if config.Privileged {
			def.Privileged = aws.Bool(config.Privileged)
		}

		if slice := config.DNS.Slice(); len(slice) > 0 {
			for _, dns := range slice {
				def.DnsServers = append(def.DnsServers, aws.String(dns))
			}
		}

		if slice := config.DNSSearch.Slice(); len(slice) > 0 {
			for _, item := range slice {
				def.DnsSearchDomains = append(def.DnsSearchDomains, aws.String(item))
			}
		}

		if cmds := config.Command.Slice(); len(cmds) > 0 {
			def.Command = []*string{}
			for _, command := range cmds {
				def.Command = append(def.Command, aws.String(command))
			}
		}

		if cmds := config.Entrypoint.Slice(); len(cmds) > 0 {
			def.EntryPoint = []*string{}
			for _, command := range cmds {
				def.EntryPoint = append(def.EntryPoint, aws.String(command))
			}
		}

		if slice := config.Environment.Slice(); len(slice) > 0 {
			def.Environment = []*ecs.KeyValuePair{}
			for _, val := range slice {
				parts := strings.SplitN(val, "=", 2)
				def.Environment = append(def.Environment, &ecs.KeyValuePair{
					Name:  aws.String(parts[0]),
					Value: aws.String(parts[1]),
				})
			}
		}

		if ports := config.Ports; len(ports) > 0 {
			def.PortMappings = []*ecs.PortMapping{}
			for _, val := range ports {
				parts := strings.Split(val, ":")
				mapping := &ecs.PortMapping{}

				// TODO: support host to map to
				if len(parts) > 0 {
					portInt, err := strconv.ParseInt(parts[0], 10, 64)
					if err != nil {
						return task, err
					}
					mapping.ContainerPort = aws.Int64(portInt)
				}

				if len(parts) > 1 {
					hostParts := strings.Split(parts[1], "/")
					portInt, err := strconv.ParseInt(hostParts[0], 10, 64)
					if err != nil {
						return task, err
					}
					mapping.HostPort = aws.Int64(portInt)

					// handle the protocol at the end of the mapping
					if len(hostParts) > 1 {
						mapping.Protocol = aws.String(hostParts[1])
					}
				}

				if len(parts) == 0 || len(parts) > 2 {
					return task, errors.New("Unsupported port mapping " + val)
				}

				def.PortMappings = append(def.PortMappings, mapping)
			}
		}

		if links := config.Links.Slice(); len(links) > 0 {
			def.Links = []*string{}
			for _, link := range links {
				def.Links = append(def.Links, aws.String(link))
			}
		}

		if vols := config.Volumes; len(vols) > 0 {
			def.MountPoints = []*ecs.MountPoint{}
			for idx, vol := range vols {
				parts := strings.Split(vol, ":")
				volumeName := fmt.Sprintf("%s-vol%d", name, idx)

				volume := ecs.Volume{
					Host: &ecs.HostVolumeProperties{
						SourcePath: aws.String(parts[0]),
					},
					Name: aws.String(volumeName),
				}

				mount := ecs.MountPoint{
					SourceVolume:  aws.String(volumeName),
					ContainerPath: aws.String(parts[1]),
				}

				if len(parts) == 3 && parts[2] == "ro" {
					mount.ReadOnly = aws.Bool(true)
				}

				task.Volumes = append(task.Volumes, &volume)
				def.MountPoints = append(def.MountPoints, &mount)
			}
		}

		if volsFrom := config.VolumesFrom; len(volsFrom) > 0 {
			def.VolumesFrom = []*ecs.VolumeFrom{}
			for _, container := range volsFrom {
				def.VolumesFrom = append(def.VolumesFrom, &ecs.VolumeFrom{
					SourceContainer: aws.String(container),
				})
			}
		}

		if config.Build != "" {
			return task, errors.New("Build directive not supported")
		}
		if config.Dockerfile != "" {
			return task, errors.New("Dockerfile directive not supported")
		}
		if config.DomainName != "" {
			return task, errors.New("DomainName directive not supported")
		}
		if config.VolumeDriver != "" {
			return task, errors.New("VolumeDriver directive not supported")
		}

		task.ContainerDefinitions = append(task.ContainerDefinitions, &def)

		// Not Implemented
		// CapAdd:[]string(nil),
		// CapDrop:[]string(nil),
		// CPUSet:"",
		// ContainerName:"",
		// Devices:[]string(nil),
		// EnvFile:project.Stringorslice{parts:[]string(nil)},
		// Labels:project.SliceorMap{parts:map[string]string(nil)},
		// LogDriver:"",
		// MemSwapLimit:0,
		// Net:"",
		// Pid:"",
		// Uts:"",
		// Ipc:"",
		// Restart:"",
		// ReadOnly:false,
		// StdinOpen:false,
		// SecurityOpt:[]string(nil),
		// Tty:false,
		// User:"",
		// Expose:[]string(nil),
		// ExternalLinks:[]string(nil),
		// LogOpt:map[string]string(nil),
		// ExtraHosts:[]string(nil)}
	}

	return task, nil
}