package image

import (
	"crypto/sha256"
	"encoding/hex"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
)

func TestDownloadDecompressesXZFileURLs(t *testing.T) {
	if _, err := exec.LookPath("xz"); err != nil {
		t.Skip("xz not available")
	}
	dir := t.TempDir()
	raw := filepath.Join(dir, "base.img")
	if err := os.WriteFile(raw, []byte("metis-xz-test"), 0o644); err != nil {
		t.Fatal(err)
	}
	compressed := raw + ".xz"
	cmd := exec.Command("xz", "-zk", raw)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("xz: %v: %s", err, string(out))
	}
	dest := filepath.Join(dir, "copy.img")
	if err := Download("file://"+compressed, dest); err != nil {
		t.Fatalf("Download: %v", err)
	}
	data, err := os.ReadFile(dest)
	if err != nil {
		t.Fatalf("ReadFile: %v", err)
	}
	if string(data) != "metis-xz-test" {
		t.Fatalf("unexpected decompressed content: %q", string(data))
	}
}

func TestDownloadAndVerifyUsesArchiveChecksumForXZ(t *testing.T) {
	if _, err := exec.LookPath("xz"); err != nil {
		t.Skip("xz not available")
	}
	dir := t.TempDir()
	raw := filepath.Join(dir, "base.img")
	if err := os.WriteFile(raw, []byte("metis-xz-test"), 0o644); err != nil {
		t.Fatal(err)
	}
	compressed := raw + ".xz"
	cmd := exec.Command("xz", "-zk", raw)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("xz: %v: %s", err, string(out))
	}
	archiveBytes, err := os.ReadFile(compressed)
	if err != nil {
		t.Fatalf("ReadFile archive: %v", err)
	}
	archiveSum := sha256.Sum256(archiveBytes)
	dest := filepath.Join(dir, "copy.img")
	localPath, err := DownloadAndVerify("file://"+compressed, dest, "sha256:"+hex.EncodeToString(archiveSum[:]))
	if err != nil {
		t.Fatalf("DownloadAndVerify: %v", err)
	}
	if localPath != dest {
		t.Fatalf("expected local path %s, got %s", dest, localPath)
	}
	data, err := os.ReadFile(dest)
	if err != nil {
		t.Fatalf("ReadFile dest: %v", err)
	}
	if string(data) != "metis-xz-test" {
		t.Fatalf("unexpected decompressed content: %q", string(data))
	}
}

func TestDownloadAndVerifyReplacesStaleBadArchiveCache(t *testing.T) {
	if _, err := exec.LookPath("xz"); err != nil {
		t.Skip("xz not available")
	}
	dir := t.TempDir()
	raw := filepath.Join(dir, "base.img")
	if err := os.WriteFile(raw, []byte("metis-xz-test"), 0o644); err != nil {
		t.Fatal(err)
	}
	compressed := raw + ".xz"
	cmd := exec.Command("xz", "-zk", raw)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Fatalf("xz: %v: %s", err, string(out))
	}
	archiveBytes, err := os.ReadFile(compressed)
	if err != nil {
		t.Fatalf("ReadFile archive: %v", err)
	}
	archiveSum := sha256.Sum256(archiveBytes)
	dest := filepath.Join(dir, "copy.img")
	staleArchive := dest + ".xz"
	if err := os.WriteFile(staleArchive, []byte("bad-cache"), 0o644); err != nil {
		t.Fatalf("WriteFile stale archive: %v", err)
	}
	if _, err := DownloadAndVerify("file://"+compressed, dest, "sha256:"+hex.EncodeToString(archiveSum[:])); err != nil {
		t.Fatalf("DownloadAndVerify with stale archive: %v", err)
	}
	data, err := os.ReadFile(dest)
	if err != nil {
		t.Fatalf("ReadFile dest: %v", err)
	}
	if string(data) != "metis-xz-test" {
		t.Fatalf("unexpected decompressed content: %q", string(data))
	}
}
