package envpool_test

import (
	"context"
	"errors"
	"reflect"
	"testing"
	"time"

	"github.com/jfraeys/fetch_ml/internal/envpool"
)

type fakeRunner struct {
	calls []call

	outputs map[string][]byte
	errs    map[string]error
}

type call struct {
	name string
	args []string
}

func (r *fakeRunner) CombinedOutput(_ context.Context, name string, args ...string) ([]byte, error) {
	r.calls = append(r.calls, call{name: name, args: append([]string(nil), args...)})
	key := name + " " + join(args)
	out := r.outputs[key]
	if err, ok := r.errs[key]; ok {
		return out, err
	}
	return out, nil
}

func join(args []string) string {
	if len(args) == 0 {
		return ""
	}
	s := args[0]
	for i := 1; i < len(args); i++ {
		s += " " + args[i]
	}
	return s
}

func TestWarmImageTag(t *testing.T) {
	p := envpool.New("")
	tag, err := p.WarmImageTag("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if tag != "fetchml-prewarm:aaaaaaaaaaaa" {
		t.Fatalf("unexpected tag: %q", tag)
	}

	if _, err := p.WarmImageTag(""); err == nil {
		t.Fatalf("expected error for empty sha")
	}
	if _, err := p.WarmImageTag("ABC"); err == nil {
		t.Fatalf("expected error for invalid sha")
	}
}

func TestImageExists_NotFoundOutputIsFalse(t *testing.T) {
	r := &fakeRunner{outputs: map[string][]byte{}, errs: map[string]error{}}
	p := envpool.New("").WithRunner(r).WithCacheTTL(10 * time.Second)

	key := "podman image inspect fetchml-prewarm:deadbeef"
	r.outputs[key] = []byte("Error: no such image fetchml-prewarm:deadbeef")
	r.errs[key] = errors.New("exit")

	exists, err := p.ImageExists(context.Background(), "fetchml-prewarm:deadbeef")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if exists {
		t.Fatalf("expected exists=false")
	}
}

func TestPrepare_SkipsWhenImageAlreadyExists(t *testing.T) {
	r := &fakeRunner{outputs: map[string][]byte{}, errs: map[string]error{}}
	p := envpool.New("").WithRunner(r).WithCacheTTL(10 * time.Second)

	inspectKey := "podman image inspect fetchml-prewarm:aaaaaaaaaaaa"
	r.outputs[inspectKey] = []byte("ok")

	err := p.Prepare(context.Background(), envpool.PrepareRequest{
		BaseImage:           "base:latest",
		TargetImage:         "fetchml-prewarm:aaaaaaaaaaaa",
		HostWorkspace:       "/tmp/ws",
		ContainerWorkspace:  "/workspace",
		DepsPathInContainer: "/workspace/requirements.txt",
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if len(r.calls) != 1 {
		t.Fatalf("expected only image inspect call, got %d", len(r.calls))
	}
	wantArgs := []string{"image", "inspect", "fetchml-prewarm:aaaaaaaaaaaa"}
	if r.calls[0].name != "podman" || !reflect.DeepEqual(r.calls[0].args, wantArgs) {
		t.Fatalf("unexpected call: %+v", r.calls[0])
	}
}

func TestPrepare_RequiresDepsUnderWorkspace(t *testing.T) {
	p := envpool.New("")
	err := p.Prepare(context.Background(), envpool.PrepareRequest{
		BaseImage:           "base:latest",
		TargetImage:         "fetchml-prewarm:aaaaaaaaaaaa",
		HostWorkspace:       "/tmp/ws",
		ContainerWorkspace:  "/workspace",
		DepsPathInContainer: "/etc/passwd",
	})
	if err == nil {
		t.Fatalf("expected error")
	}
}
