// SPDX-FileCopyrightText: 2023 Luke Granger-Brown <depot@lukegb.com>
//
// SPDX-License-Identifier: Apache-2.0

package main

import (
	"context"
	"flag"
	"log"
	"strings"
	"sync"

	"hg.lukegb.com/lukegb/depot/go/nix/nixbuild"
	"hg.lukegb.com/lukegb/depot/go/nix/nixdrv"
	"hg.lukegb.com/lukegb/depot/go/nix/nixpool"
	"hg.lukegb.com/lukegb/depot/go/nix/nixstore"
)

type remoteDefinition struct {
	URL                  string
	PermittedResolutions int
	PermittedBuilds      int
	SupportedPlatforms   map[string]bool
	SupportedFeatures    map[string]bool
	RequiredFeatures     []map[string]bool
}

var (
	debugFlag = flag.Bool("b", false, "debug")
)

func bmain() {
	ctx := context.Background()
	remote := remoteDefinition{
		URL:                  "ssh-ng://lukegb@eu.nixbuild.net?insecure-allow-any-ssh-host-key=true&privkey=/var/lib/secrets/id_ed25519_nixbuild/secret",
		PermittedResolutions: 100,
		PermittedBuilds:      100,
		SupportedPlatforms:   map[string]bool{"x86_64-linux": true, "aarch64-linux": true},
	}
	local := remoteDefinition{
		URL:                  "unix://",
		PermittedResolutions: 100,
		PermittedBuilds:      100,
	}
	// d = remoteDefinition{
	// 	URL:                  "ssh-ng://lukegb@whitby.tvl.fyi?insecure-allow-any-ssh-host-key=true&privkey=/home/lukegb/.ssh/id_ed25519",
	// 	PermittedResolutions: 64,
	// 	PermittedBuilds:      64,
	// 	SupportedPlatforms:   map[string]bool{"x86_64-linux": true},
	// }
	remoteFactory, err := nixpool.DaemonDialer(ctx, remote.URL)
	if err != nil {
		log.Fatalf("creating dialer for %v: %v", remote.URL, err)
	}
	remoteConn, err := remoteFactory()
	if err != nil {
		log.Fatalf("dialing %v: %v", remote.URL, err)
	}
	defer remoteConn.Close()

	localFactory, err := nixpool.DaemonDialer(ctx, local.URL)
	if err != nil {
		log.Fatalf("creating dialer for %v: %v", local.URL, err)
	}
	localConn, err := localFactory()
	if err != nil {
		log.Fatalf("dialing %v: %v", local.URL, err)
	}
	defer localConn.Close()

	//const storePath = "/nix/store/pl5izkcgln1kvy8hv1850888my0b80qs-golib-golang.org_x_crypto_ed25519"
	const storePath = "/nix/store/1mpp8vsq5wl5zd6nzallr4dc5jm342yn-factorio_alpha_x64-1.1.88.tar.xz"
	ni, err := localConn.NARInfo(storePath)
	if err != nil {
		log.Fatalf("localConn.NARInfo(%q): %v", storePath, err)
	}
	log.Println(ni, err)

	rc, err := localConn.NARFromPath(storePath)
	if err != nil {
		log.Fatalf("localConn.NARFromPath(%q): %v", storePath, err)
	}

	if err := remoteConn.AddToStoreNar(ni, rc); err != nil {
		log.Fatalf("remoteConn.AddToStoreNar: %v", err)
	}
	rc.Close()
}

func main() {
	flag.Parse()
	if *debugFlag {
		bmain()
	}

	ctx := context.Background()

	remoteDefs := []remoteDefinition{{
		URL:                  "unix://",
		PermittedResolutions: 64,
		PermittedBuilds:      64,
		SupportedPlatforms:   map[string]bool{"x86_64-linux": true, "i686-linux": true},
		SupportedFeatures:    map[string]bool{"kvm": true},
		RequiredFeatures: []map[string]bool{
			map[string]bool{"kvm": true},
		},
		//	}, {
		//		URL:                  "ssh-ng://lukegb@whitby.tvl.fyi?insecure-allow-any-ssh-host-key=true&privkey=/home/lukegb/.ssh/id_ed25519",
		//		PermittedResolutions: 64,
		//		PermittedBuilds:      64,
		//		SupportedPlatforms:   map[string]bool{"x86_64-linux": true},
		//		SupportedFeatures:    map[string]bool{"big-parallel": true},
	}, {
		URL:                  "ssh-ng://lukegb@eu.nixbuild.net?insecure-allow-any-ssh-host-key=true&privkey=/var/lib/secrets/id_ed25519_nixbuild/secret",
		PermittedResolutions: 100,
		PermittedBuilds:      100,
		SupportedPlatforms:   map[string]bool{"x86_64-linux": true, "aarch64-linux": true, "i686-linux": true},
		SupportedFeatures:    map[string]bool{"big-parallel": true},
	}}
	var builders []*nixbuild.Builder
	var resolvers []nixbuild.Resolver
	for _, d := range remoteDefs {
		factory, err := nixpool.DaemonDialer(ctx, d.URL)
		if err != nil {
			log.Fatalf("creating dialer for %v: %w", d.URL, err)
		}
		if d.PermittedResolutions > 0 {
			resolverPool := nixpool.New(ctx, factory, d.PermittedResolutions)
			resolvers = append(resolvers, nixbuild.PeerResolver{PeerFetcher: nixbuild.PeerFetcher{Pool: resolverPool}})
		}
		if d.PermittedBuilds > 0 {
			builderPool := nixpool.New(ctx, factory, d.PermittedBuilds)
			builders = append(builders, &nixbuild.Builder{Pool: builderPool, SupportedPlatforms: d.SupportedPlatforms, SupportedFeatures: d.SupportedFeatures, RequiredFeatures: d.RequiredFeatures})
		}
	}
	target := &nixbuild.PeerTarget{
		PeerFetcher:     resolvers[0].(nixbuild.PeerResolver).PeerFetcher,
		ActivityTracker: nixstore.NewActivityTracker(),
	}

	cfg := nixbuild.Config{
		Target:                        target,
		ResolveOnTarget:               true,
		Resolvers:                     resolvers,
		Builders:                      builders,
		ResolveDependenciesOnBuilders: false,
	}
	at := nixstore.NewActivityTracker()
	coord := nixbuild.NewCoordinator(cfg, at)

	localResolver := nixdrv.LocalFSResolver{}

	var wg sync.WaitGroup
	for _, arg := range flag.Args() {
		arg := arg
		wg.Add(1)
		go func() {
			defer wg.Done()
			var wi *nixbuild.WorkItem
			if strings.HasSuffix(arg, ".drv") {
				drv, err := localResolver.LoadDerivation(ctx, arg)
				if err != nil {
					log.Fatalf("LoadDerivation(%q): %v", arg, err)
				}
				bd, err := drv.ToBasicDerivation(ctx, localResolver)
				if err != nil {
					log.Fatalf("drv.ToBasicDerivation(): %v", err)
				}

				wi = coord.AddDerivationWork(ctx, bd, arg)
			} else {
				wi = coord.AddWork(ctx, arg)
			}
			<-wi.Done()
		}()
	}
	wg.Wait()
}