package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"dagger.io/dagger"
	platformFormat "github.com/containerd/containerd/platforms"
	"golang.org/x/sync/errgroup"
)

var platforms = []dagger.Platform{
	"linux/amd64",
	"linux/arm64",
}

func architectureOf(platform dagger.Platform) string {
	return platformFormat.MustParse(string(platform)).Architecture
}

func Build(ctx context.Context) error {
	client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout))
	if err != nil {
		return err
	}
	defer client.Close()

	containers := make([]*dagger.Container, 0, len(platforms))

	egrp, _ := errgroup.WithContext(ctx)

	ctx = context.Background()

	shuttleGit := client.
		Git("git@github.com:lunarway/shuttle.git", dagger.GitOpts{
			KeepGitDir: true,
		}).
		Tag("v0.17.2").
		Tree(dagger.GitRefTreeOpts{
			SSHAuthSocket: client.Host().UnixSocket(os.Getenv("SSH_AUTH_SOCK")),
		})

	for _, platform := range platforms {
		platform := platform

		egrp.Go(func() error {
			golang := client.Container().From("golang:1.20.3")

			shuttleImg := golang.
				WithDirectory("/app", shuttleGit).
				WithWorkdir("/app").
				WithEnvVariable("CGO_ENABLED", "0").
				WithEnvVariable("GOOS", "linux").
				WithEnvVariable("GOARCH", architectureOf(platform)).
				WithExec([]string{"go", "build"})

			if _, err := shuttleImg.ExitCode(ctx); err != nil {
				log.Printf("%v", err)
				return err
			}

			shuttle := shuttleImg.Directory("/app").
				File("shuttle")

			docker := client.
				Container(dagger.ContainerOpts{
					Platform: platform,
				}).
				From("docker:cli").
				File("/usr/local/bin/docker")

			image := client.
				Container(dagger.ContainerOpts{
					Platform: platform,
				}).
				From("golang:1.20.3").
				WithExec([]string{
					"apt", "update",
				}).
				WithExec([]string{
					"apt", "install", "-y", "curl", "build-essential",
				}).
				WithEnvVariable("RUSTUP_HOME", "/usr/local/rustup").
				WithEnvVariable("CARGO_HOME", "/usr/local/cargo").
				WithExec([]string{
					"bash", "-c", "curl https://sh.rustup.rs -sSf | bash -s -- -y",
				})

			path, err := image.EnvVariable(ctx, "PATH")
			if err != nil {
				return err
			}

			image = image.
				WithEnvVariable(
					"PATH", fmt.Sprintf("/usr/local/cargo/bin:%s", path),
				).
				WithExec([]string{"rustup", "toolchain", "install", "nightly"}).
				WithExec([]string{"rustup", "default", "nightly"}).
				WithWorkdir("/app").
				WithFile("/usr/local/bin/shuttle", shuttle).
				WithExec([]string{"shuttle", "version"})
			if _, err := image.ExitCode(ctx); err != nil {
				log.Printf("%v", err)
				return err
			}

			if _, err := image.WithExec([]string{"cargo", "--version"}).ExitCode(ctx); err != nil {
				log.Printf("%v", err)
				return err
			}

			image = image.WithFile("/usr/bin/docker", docker)
			if _, err := image.ExitCode(ctx); err != nil {
				log.Printf("%v", err)
				return err
			}

			containers = append(containers, image)

			return nil
		})

		time.Sleep(5 * time.Second)
	}

	if err := egrp.Wait(); err != nil {
		log.Printf("%v", err)
		return err
	}

	tag := time.Now().UnixMilli()

	imageTag, err := client.Container().
		Publish(
			ctx,
			fmt.Sprintf("docker.io/kasperhermansen/shuttle-drone:%d", tag),
			dagger.ContainerPublishOpts{
				PlatformVariants: containers,
			})
	if err != nil {
		log.Printf("%v", err)
		return err
	}

	log.Printf("imageTag: %s\n", imageTag)

	return nil
}