package main

import (
	"context"
	"dagger/http-nu/internal/dagger"
)

type HttpNu struct{}

func (m *HttpNu) withCaches(container *dagger.Container, targetSuffix string) *dagger.Container {
	// Separate caches per target
	registryCache := dag.CacheVolume("dagger-cargo-registry-" + targetSuffix)
	gitCache := dag.CacheVolume("dagger-cargo-git-" + targetSuffix)
	targetCache := dag.CacheVolume("dagger-cargo-target-" + targetSuffix)

	return container.
		WithMountedCache("/root/.cargo/registry", registryCache).
		WithMountedCache("/root/.cargo/git", gitCache).
		WithMountedCache("/app/target", targetCache)
}

func (m *HttpNu) Upload(
	ctx context.Context,
	// +ignore=["**", "!Cargo.toml", "!Cargo.lock", "!src/**", "!xs.nu", "!scripts/**", "!tests/test_plugin/**"]
	src *dagger.Directory) *dagger.Directory {
	return src
}

func (m *HttpNu) DarwinEnv(
	ctx context.Context,
	src *dagger.Directory) *dagger.Container {
	return m.withCaches(
		dag.Container().
			From("joseluisq/rust-linux-darwin-builder:latest").
			WithMountedDirectory("/app", src).
			WithWorkdir("/app"),
		"darwin-arm64",
	)
}

func (m *HttpNu) DarwinBuild(ctx context.Context, src *dagger.Directory, version string) *dagger.File {
	container := m.DarwinEnv(ctx, src).
		WithExec([]string{"rustup", "update", "stable"}).
		WithExec([]string{"rustup", "default", "stable"}).
		WithExec([]string{"rustup", "target", "add", "aarch64-apple-darwin"}).
		WithExec([]string{"./scripts/cross-build-darwin.sh", "--release"})

	container = container.WithExec([]string{"sh", "-c", `
		mkdir -p /tmp/http-nu-` + version + `
		cp /app/target/aarch64-apple-darwin/release/http-nu /tmp/http-nu-` + version + `/
		cd /tmp
		tar -czf http-nu-` + version + `-darwin-arm64.tar.gz http-nu-` + version + `
	`})

	return container.File("/tmp/http-nu-" + version + "-darwin-arm64.tar.gz")
}

func (m *HttpNu) WindowsEnv(
	ctx context.Context,
	src *dagger.Directory) *dagger.Container {
	return m.withCaches(
		dag.Container().
			From("joseluisq/rust-linux-darwin-builder:latest").
			WithExec([]string{"apt", "update"}).
			WithExec([]string{"apt", "install", "-y", "nasm", "gcc-mingw-w64-i686", "mingw-w64", "mingw-w64-tools"}).
			WithExec([]string{"rustup", "target", "add", "x86_64-pc-windows-gnu"}).
			WithEnvVariable("CARGO_BUILD_TARGET", "x86_64-pc-windows-gnu").
			WithEnvVariable("CC_x86_64_pc_windows_gnu", "x86_64-w64-mingw32-gcc").
			WithEnvVariable("CXX_x86_64_pc_windows_gnu", "x86_64-w64-mingw32-g++").
			WithEnvVariable("AR_x86_64_pc_windows_gnu", "x86_64-w64-mingw32-gcc-ar").
			WithEnvVariable("DLLTOOL_x86_64_pc_windows_gnu", "x86_64-w64-mingw32-dlltool").
			WithEnvVariable("CFLAGS_x86_64_pc_windows_gnu", "-m64").
			WithEnvVariable("ASM_NASM_x86_64_pc_windows_gnu", "/usr/bin/nasm").
			WithEnvVariable("AWS_LC_SYS_PREBUILT_NASM", "0").
			WithMountedDirectory("/app", src).
			WithWorkdir("/app"),
		"windows-amd64",
	)
}

func (m *HttpNu) WindowsBuild(ctx context.Context, src *dagger.Directory, version string) *dagger.File {
	container := m.WindowsEnv(ctx, src).
		WithExec([]string{"rustup", "update", "stable"}).
		WithExec([]string{"rustup", "default", "stable"}).
		WithExec([]string{"rustup", "target", "add", "x86_64-pc-windows-gnu"}).
		WithExec([]string{"cargo", "check", "--release", "--tests", "--target", "x86_64-pc-windows-gnu"}).
		WithExec([]string{"cargo", "build", "--release", "--target", "x86_64-pc-windows-gnu"})

	container = container.WithExec([]string{"sh", "-c", `
		mkdir -p /tmp/http-nu-` + version + `
		cp /app/target/x86_64-pc-windows-gnu/release/http-nu.exe /tmp/http-nu-` + version + `/
		cd /tmp
		tar -czf http-nu-` + version + `-windows-amd64.tar.gz http-nu-` + version + `
	`})

	return container.File("/tmp/http-nu-" + version + "-windows-amd64.tar.gz")
}

func (m *HttpNu) LinuxArm64Env(
	ctx context.Context,
	src *dagger.Directory) *dagger.Container {
	return m.withCaches(
		dag.Container().
			From("messense/rust-musl-cross:aarch64-musl").
			WithMountedDirectory("/app", src).
			WithWorkdir("/app"),
		"linux-arm64",
	)
}

func (m *HttpNu) LinuxArm64Build(ctx context.Context, src *dagger.Directory, version string) *dagger.File {
	container := m.LinuxArm64Env(ctx, src).
		WithExec([]string{"cargo", "build", "--release", "--target", "aarch64-unknown-linux-musl"})

	container = container.WithExec([]string{"sh", "-c", `
		mkdir -p /tmp/http-nu-` + version + `
		cp /app/target/aarch64-unknown-linux-musl/release/http-nu /tmp/http-nu-` + version + `/
		cd /tmp
		tar -czf http-nu-` + version + `-linux-arm64.tar.gz http-nu-` + version + `
	`})

	return container.File("/tmp/http-nu-" + version + "-linux-arm64.tar.gz")
}

func (m *HttpNu) LinuxAmd64Env(
	ctx context.Context,
	src *dagger.Directory) *dagger.Container {
	return m.withCaches(
		dag.Container().
			From("messense/rust-musl-cross:x86_64-musl").
			WithMountedDirectory("/app", src).
			WithWorkdir("/app"),
		"linux-amd64",
	)
}

func (m *HttpNu) LinuxAmd64Build(ctx context.Context, src *dagger.Directory, version string) *dagger.File {
	container := m.LinuxAmd64Env(ctx, src).
		WithExec([]string{"cargo", "build", "--release", "--target", "x86_64-unknown-linux-musl"})

	container = container.WithExec([]string{"sh", "-c", `
		mkdir -p /tmp/http-nu-` + version + `
		cp /app/target/x86_64-unknown-linux-musl/release/http-nu /tmp/http-nu-` + version + `/
		cd /tmp
		tar -czf http-nu-` + version + `-linux-amd64.tar.gz http-nu-` + version + `
	`})

	return container.File("/tmp/http-nu-" + version + "-linux-amd64.tar.gz")
}
