package mage_helpers

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"strings"
	"syscall"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func SamStartApi(ctx context.Context, handler string, profile string, debug bool) error {
	stopRunningSamDocker()

	usr, _ := user.Current()
	homeDir := usr.HomeDir
	delveDir := homeDir + "/go/delve/"

	commandArgs := []string{
		`local`,
		`start-api`,
	}

	if debug {
		commandArgs = append(commandArgs, `--debug-port=5986`,
			fmt.Sprintf(`--debugger-path=%s`, delveDir),
			`--debug-args=-delveAPI=2`)
	}

	commandArgs = append(commandArgs,
		fmt.Sprintf(`--profile=%v`, profile),
		fmt.Sprintf(`--template=core/%v/template.yml`, handler),
		`--region=af-south-1`)

	err := runLongRunningSubProcess(ctx, "sam", commandArgs...)
	if err != nil {
		return err
	}

	return nil
}

func SamInvokeSQS(ctx context.Context, handler string, function string, profile string) error {
	stopRunningSamDocker()

	usr, _ := user.Current()
	homeDir := usr.HomeDir
	delveDir := homeDir + "/go/delve/"

	commandArgs := []string{
		`local`,
		`invoke`,
		`-e`,
		fmt.Sprintf(`core/%v/sqs.input.json`, handler),
		function,
		`--debug-port=5986`,
		fmt.Sprintf(`--debugger-path=%s`, delveDir),
		`--debug-args=-delveAPI=2`,
		fmt.Sprintf(`--profile=%v`, profile),
		fmt.Sprintf(`--template=core/%v/template.yml`, handler),
		`--region=af-south-1`,
	}

	err := runLongRunningSubProcess(ctx, "sam", commandArgs...)
	if err != nil {
		return err
	}

	return nil
}

func runLongRunningSubProcess(ctx context.Context, name string, arg ...string) error {
	cancelContext, cancel := context.WithCancel(ctx)
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	defer func() {
		signal.Stop(signalChan)
		cancel()
	}()

	fmt.Println(fmt.Sprintf("Running command: %s %s", name, strings.Join(arg, " ")))
	cmd := exec.CommandContext(cancelContext, name, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	go func() {
		select {
		case <-signalChan: // first signal, cancel context
			fmt.Println("Stopping process")
			if err := cmd.Process.Signal(syscall.SIGINT); err != nil {
				log.Fatal("failed to kill process: ", err)
			}
			cancel()
		case <-cancelContext.Done():
		}
		<-signalChan // second signal, hard exit
		os.Exit(1)
	}()

	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func stopRunningSamDocker() {
	cli, err := client.NewClientWithOpts(client.FromEnv)
	if err != nil {
		panic(err)
	}

	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
	if err != nil {
		panic(err)
	}

	for _, container := range containers {
		mustStop := false
		if strings.Contains(container.Command, "/var/rapid/aws-lambda-rie") {
			mustStop = true
		} else {
			for _, port := range container.Ports {
				if port.PrivatePort == 5986 {
					mustStop = true
					break
				}
			}
		}
		if mustStop {
			err = cli.ContainerStop(context.Background(), container.ID, nil)
			if err != nil {
				panic(err)
			}
			err = cli.ContainerRemove(context.Background(), container.ID, types.ContainerRemoveOptions{})
			if err != nil {
				panic(err)
			}
			log.Printf("Stopped and removed container %s\n", container.ID)
		}
	}

}