package api

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func TestCustomKVMImageCreateRejectsInvalidSource(t *testing.T) {
	payload := map[string]string{
		"name":        "Invalid Source",
		"distro":      "ubuntu",
		"release":     "noble",
		"arch":        runtime.GOARCH,
		"url":         "file:///etc/passwd",
		"provisioner": "linux-cloud-init",
	}
	body, err := json.Marshal(payload)
	if err != nil {
		t.Fatal(err)
	}
	request := httptest.NewRequest(http.MethodPost, "/api/images/custom", bytes.NewReader(body))
	response := httptest.NewRecorder()

	HandleCustomKVMImages(response, request)

	if response.Code != http.StatusBadRequest {
		t.Fatalf("status = %d, want %d; body=%s", response.Code, http.StatusBadRequest, response.Body.String())
	}
}

func TestCustomKVMImageCreateRejectsArchitectureMismatch(t *testing.T) {
	otherArch := "arm64"
	if runtime.GOARCH == otherArch {
		otherArch = "amd64"
	}
	payload := map[string]string{
		"name":        "Wrong Architecture",
		"distro":      "ubuntu",
		"release":     "noble",
		"arch":        otherArch,
		"url":         "https://example.test/image.qcow2",
		"provisioner": "linux-cloud-init",
	}
	body, err := json.Marshal(payload)
	if err != nil {
		t.Fatal(err)
	}
	request := httptest.NewRequest(http.MethodPost, "/api/images/custom", bytes.NewReader(body))
	response := httptest.NewRecorder()

	HandleCustomKVMImages(response, request)

	if response.Code != http.StatusBadRequest {
		t.Fatalf("status = %d, want %d; body=%s", response.Code, http.StatusBadRequest, response.Body.String())
	}
}

func TestCustomLXCImageCreateRejectsInvalidSource(t *testing.T) {
	payload := map[string]string{
		"type":    "lxc",
		"name":    "Invalid LXC Source",
		"distro":  "alpine",
		"release": "3.21",
		"arch":    runtime.GOARCH,
		"url":     "file:///tmp/rootfs.tar.xz",
	}
	body, err := json.Marshal(payload)
	if err != nil {
		t.Fatal(err)
	}
	request := httptest.NewRequest(http.MethodPost, "/api/images/custom", bytes.NewReader(body))
	response := httptest.NewRecorder()

	HandleCustomKVMImages(response, request)

	if response.Code != http.StatusBadRequest {
		t.Fatalf("status = %d, want %d; body=%s", response.Code, http.StatusBadRequest, response.Body.String())
	}
}

func TestCustomImageCreateRejectsPrivateNetworkSource(t *testing.T) {
	for _, imageType := range []string{"lxc", "kvm"} {
		t.Run(imageType, func(t *testing.T) {
			payload := map[string]string{
				"type":        imageType,
				"name":        "Private Network Source",
				"distro":      "ubuntu",
				"release":     "noble",
				"arch":        runtime.GOARCH,
				"url":         "http://169.254.169.254/latest/meta-data",
				"provisioner": "linux-cloud-init",
			}
			body, err := json.Marshal(payload)
			if err != nil {
				t.Fatal(err)
			}
			request := httptest.NewRequest(http.MethodPost, "/api/images/custom", bytes.NewReader(body))
			response := httptest.NewRecorder()

			HandleCustomKVMImages(response, request)

			if response.Code != http.StatusBadRequest {
				t.Fatalf("status = %d, want %d; body=%s", response.Code, http.StatusBadRequest, response.Body.String())
			}
		})
	}
}

func TestOfficialLXCImageCachePathUsesAllowlist(t *testing.T) {
	cachePath, ok := officialLXCImageCachePath("debian-trixie")
	if !ok {
		t.Fatal("known template cache path was rejected")
	}
	normalized := filepath.ToSlash(cachePath)
	if !strings.Contains(normalized, "/debian/trixie/") {
		t.Fatalf("cache path = %q, want Debian trixie path", cachePath)
	}
	for _, templateID := range []string{
		"../../../etc",
		"custom-lxc-attacker",
		"debian-trixie/../../etc",
	} {
		if cachePath, ok := officialLXCImageCachePath(templateID); ok || cachePath != "" {
			t.Fatalf("officialLXCImageCachePath(%q) = %q, %v; want rejection", templateID, cachePath, ok)
		}
	}
}
