package images

import (
	"bytes"
	"encoding/json"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

// a 1x1 transparent PNG.
var pngBytes = []byte{
	0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4,
	0x89, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x62, 0x00, 0x01, 0x00, 0x00,
	0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
	0x42, 0x60, 0x82,
}

func uploadReq(t *testing.T, field string, data []byte) *http.Request {
	t.Helper()
	var buf bytes.Buffer
	mw := multipart.NewWriter(&buf)
	fw, err := mw.CreateFormFile(field, "x.png")
	if err != nil {
		t.Fatal(err)
	}
	fw.Write(data)
	mw.Close()
	req := httptest.NewRequest(http.MethodPost, "/", &buf)
	req.Header.Set("Content-Type", mw.FormDataContentType())
	return req
}

func TestUploadAndServe(t *testing.T) {
	h, err := New(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}
	r := h.Routes()

	// Upload a PNG → expect a JSON url under /api/images/.
	rec := httptest.NewRecorder()
	r.ServeHTTP(rec, uploadReq(t, "image", pngBytes))
	if rec.Code != http.StatusOK {
		t.Fatalf("upload code=%d body=%s", rec.Code, rec.Body)
	}
	var resp struct{ URL string }
	if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
		t.Fatal(err)
	}
	if !strings.HasPrefix(resp.URL, "/api/images/") || !strings.HasSuffix(resp.URL, ".png") {
		t.Fatalf("unexpected url %q", resp.URL)
	}

	// The same content uploaded again dedupes to the same URL.
	rec2 := httptest.NewRecorder()
	r.ServeHTTP(rec2, uploadReq(t, "image", pngBytes))
	var resp2 struct{ URL string }
	json.Unmarshal(rec2.Body.Bytes(), &resp2)
	if resp2.URL != resp.URL {
		t.Fatalf("expected dedup to same url, got %q vs %q", resp2.URL, resp.URL)
	}

	// Fetch it back.
	name := strings.TrimPrefix(resp.URL, "/api/images/")
	rec3 := httptest.NewRecorder()
	r.ServeHTTP(rec3, httptest.NewRequest(http.MethodGet, "/"+name, nil))
	if rec3.Code != http.StatusOK {
		t.Fatalf("serve code=%d", rec3.Code)
	}
	if !bytes.Equal(rec3.Body.Bytes(), pngBytes) {
		t.Fatal("served bytes differ from uploaded")
	}
}

func TestUploadRejectsNonImage(t *testing.T) {
	h, _ := New(t.TempDir())
	r := h.Routes()
	rec := httptest.NewRecorder()
	r.ServeHTTP(rec, uploadReq(t, "image", []byte("this is plainly not an image at all")))
	if rec.Code != http.StatusUnsupportedMediaType {
		t.Fatalf("expected 415, got %d", rec.Code)
	}
}

func TestServeMissing(t *testing.T) {
	h, _ := New(t.TempDir())
	r := h.Routes()
	rec := httptest.NewRecorder()
	r.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/deadbeef.png", nil))
	if rec.Code != http.StatusNotFound {
		t.Fatalf("expected 404, got %d", rec.Code)
	}
}
