// Copyright 2015-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

// Package localCommand defines the subcommands for local workflows
package localCommand

import (
	"fmt"

	app "github.com/aws/amazon-ecs-cli/ecs-cli/modules"
	"github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/local"
	project "github.com/aws/amazon-ecs-cli/ecs-cli/modules/cli/local/localproject"
	"github.com/aws/amazon-ecs-cli/ecs-cli/modules/commands/flags"
	"github.com/aws/amazon-ecs-cli/ecs-cli/modules/commands/usage"
	"github.com/urfave/cli"
)

const (
	createCmdName = "create"
	upCmdName     = "up"
	psCmdName     = "ps"
	downCmdName   = "down"
)

// LocalCommand provides a list of commands that operate on a task-definition
// file (accepted formats: JSON, YAML, CloudFormation).
func LocalCommand() cli.Command {
	return cli.Command{
		Name:   "local",
		Usage:  usage.Local,
		Before: app.BeforeApp,
		Flags:  flags.AppendFlags(flags.OptECSProfileFlag(), flags.OptAWSProfileFlag(), flags.OptRegionFlag()),
		Subcommands: []cli.Command{
			createCommand(),
			upCommand(),
			downCommand(),
			psCommand(),
		},
	}
}

func createCommand() cli.Command {
	return cli.Command{
		Name:   createCmdName,
		Usage:  usage.LocalCreate,
		Before: app.BeforeApp,
		Action: local.Create,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionFile),
				Usage: flagDescription(flags.TaskDefinitionFile, createCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionRemote),
				Usage: flagDescription(flags.TaskDefinitionRemote, createCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.Output),
				Usage: flagDescription(flags.Output, createCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.ForceFlag),
				Usage: flagDescription(flags.ForceFlag, createCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.UseRole),
				Usage: flagDescription(flags.UseRole, createCmdName),
			},
		},
	}
}

func upCommand() cli.Command {
	return cli.Command{
		Name:   upCmdName,
		Usage:  usage.LocalUp,
		Action: local.Up,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionCompose),
				Usage: flagDescription(flags.TaskDefinitionCompose, upCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionFile),
				Usage: flagDescription(flags.TaskDefinitionFile, upCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionRemote),
				Usage: flagDescription(flags.TaskDefinitionRemote, upCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.Output),
				Usage: flagDescription(flags.Output, upCmdName),
			},
			cli.StringSliceFlag{
				Name:  flagName(flags.ComposeOverride),
				Usage: flagDescription(flags.ComposeOverride, upCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.ForceFlag),
				Usage: flagDescription(flags.ForceFlag, upCmdName),
			},
		},
	}
}

func psCommand() cli.Command {
	return cli.Command{
		Name:   psCmdName,
		Usage:  usage.LocalPs,
		Action: local.Ps,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionFile),
				Usage: flagDescription(flags.TaskDefinitionFile, psCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionRemote),
				Usage: flagDescription(flags.TaskDefinitionRemote, psCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.All),
				Usage: flagDescription(flags.All, psCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.JSON),
				Usage: flagDescription(flags.JSON, psCmdName),
			},
		},
	}
}

func downCommand() cli.Command {
	return cli.Command{
		Name:   downCmdName,
		Usage:  usage.LocalDown,
		Action: local.Down,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionFile),
				Usage: flagDescription(flags.TaskDefinitionFile, downCmdName),
			},
			cli.StringFlag{
				Name:  flagName(flags.TaskDefinitionRemote),
				Usage: flagDescription(flags.TaskDefinitionRemote, downCmdName),
			},
			cli.BoolFlag{
				Name:  flagName(flags.All),
				Usage: flagDescription(flags.All, downCmdName),
			},
		},
	}
}

func flagName(longName string) string {
	m := map[string]string{
		flags.TaskDefinitionCompose: flags.TaskDefinitionCompose + ",c",
		flags.TaskDefinitionFile:    flags.TaskDefinitionFile + ",f",
		flags.TaskDefinitionRemote:  flags.TaskDefinitionRemote + ",t",
		flags.Output:                flags.Output + ",o",
		flags.ComposeOverride:       flags.ComposeOverride,
		flags.JSON:                  flags.JSON,
		flags.All:                   flags.All,
		flags.ForceFlag:             flags.ForceFlag,
		flags.UseRole:               flags.UseRole,
	}
	return m[longName]
}

func flagDescription(longName, cmdName string) string {
	m := map[string]map[string]string{
		flags.TaskDefinitionCompose: {
			upCmdName: "Specifies the filename `value` that contains the Docker Compose content to run locally.",
		},
		flags.TaskDefinitionFile: {
			createCmdName: fmt.Sprintf("Specifies the filename `value` that contains the task definition JSON to convert to a Docker Compose file. If one is not specified, the ECS CLI will look for %s.", project.LocalInFileName),
			upCmdName:     fmt.Sprintf("Specifies the filename `value` containing the task definition JSON to convert and run locally.  If one is not specified, the ECS CLI will look for %s.", project.LocalInFileName),
			psCmdName:     fmt.Sprintf("Lists all running containers matching the task definition filename `value`. If one is not specified, the ECS CLI will list containers started with the task definition filename %s.", project.LocalInFileName),
			downCmdName:   fmt.Sprintf("Stops and removes all running containers matching the task definition filename `value`. If one is not specified, the ECS CLI removes all running containers matching the task definition filename %s.", project.LocalInFileName),
		},
		flags.TaskDefinitionRemote: {
			createCmdName: "Specifies the full Amazon Resource Name (ARN) or family:revision `value` of the task definition to convert to a Docker Compose file. If you specify a task definition family without a revision, the latest revision is used.",
			upCmdName:     "Specifies the full Amazon Resource Name (ARN) or family:revision `value` of the task definition to convert and run locally. If you specify a task definition family without a revision, the latest revision is used.",
			psCmdName:     "Lists all running containers matching the task definition Amazon Resource Name (ARN) or family:revision `value`. If you specify a task definition family without a revision, the latest revision is used.",
			downCmdName:   "Stops and removes all running containers matching the task definition Amazon Resource Name (ARN) or family:revision `value`. If you specify a task definition family without a revision, the latest revision is used.",
		},
		flags.ComposeOverride: {
			upCmdName: "Specifies the local Docker Compose override filename `value` to use.",
		},
		flags.Output: {
			createCmdName: fmt.Sprintf("Specifies the local filename `value` to write the Docker Compose file to. If one is not specified, the default is %s.", project.LocalOutDefaultFileName),
			upCmdName:     fmt.Sprintf("Specifies the local filename `value` to write the Docker Compose file to. If one is not specified, the default is %s.", project.LocalOutDefaultFileName),
		},
		flags.JSON: {
			psCmdName: "Sets the output to JSON format.",
		},
		flags.All: {
			psCmdName:   "Lists all locally running containers.",
			downCmdName: "Stops and removes all locally running containers.",
		},
		flags.ForceFlag: {
			createCmdName: fmt.Sprintf("Overwrite output docker compose file if it exists. Default compose file is %s.", project.LocalOutDefaultFileName),
			upCmdName:     fmt.Sprintf("Overwrite output docker compose file if it exists. Default compose file is %s.", project.LocalOutDefaultFileName),
		},
		flags.UseRole: {
		    createCmdName: "Uses the task role ARN instead of temporary credentials.",
		},
	}
	return m[longName][cmdName]
}
