import { beforeEach, describe, expect, mock, test } from "bun:test";
import { Hono } from "hono";
import { createTestDb } from "../helpers/db.ts";

// Mock storage service before importing routes
const mockUploadImage = mock(() => Promise.resolve());
mock.module("../../src/server/services/storage.service", () => ({
	uploadImage: mockUploadImage,
	deleteImage: mock(() => Promise.resolve()),
	getImageUrl: mock(() => Promise.resolve("https://s3.example.com/test.png")),
	withImageUrl: mock((r: any) => Promise.resolve({ ...r, imageUrl: null })),
	withImageUrls: mock((rs: any[]) =>
		Promise.resolve(rs.map((r) => ({ ...r, imageUrl: null }))),
	),
}));

// Also mock image service for from-url test
const mockFetchImageFromUrl = mock(() =>
	Promise.resolve({
		filename: "test.png",
		sourceUrl: "https://example.com/img.png",
	}),
);
mock.module("../../src/server/services/image.service", () => ({
	fetchImageFromUrl: mockFetchImageFromUrl,
}));

const { imageRoutes } = await import("../../src/server/routes/images.ts");

let app: Hono;

beforeEach(async () => {
	const { db, userId } = await createTestDb();
	app = new Hono();
	app.use("*", async (c, next) => {
		c.set("db", db);
		c.set("userId", userId);
		await next();
	});
	app.route("/api/images", imageRoutes);
	mockUploadImage.mockClear();
	mockFetchImageFromUrl.mockClear();
});

describe("POST /api/images/from-url", () => {
	test("returns 400 for missing URL", async () => {
		const res = await app.request("/api/images/from-url", {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({}),
		});
		expect(res.status).toBe(400);
	});

	test("returns 400 for invalid URL", async () => {
		const res = await app.request("/api/images/from-url", {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ url: "not-a-url" }),
		});
		expect(res.status).toBe(400);
	});
});

describe("POST /api/images", () => {
	test("returns 400 when no image file provided", async () => {
		const formData = new FormData();
		const res = await app.request("/api/images", {
			method: "POST",
			body: formData,
		});
		expect(res.status).toBe(400);
		const json = await res.json();
		expect(json.error).toBe("No image file provided");
	});

	test("returns 400 for invalid file type", async () => {
		const formData = new FormData();
		formData.append(
			"image",
			new Blob(["test"], { type: "text/plain" }),
			"test.txt",
		);
		const res = await app.request("/api/images", {
			method: "POST",
			body: formData,
		});
		expect(res.status).toBe(400);
		const json = await res.json();
		expect(json.error).toContain("Invalid file type");
	});

	test("uploads valid image and calls storage service", async () => {
		const formData = new FormData();
		const pngBlob = new Blob([new Uint8Array([0x89, 0x50, 0x4e, 0x47])], {
			type: "image/png",
		});
		formData.append("image", pngBlob, "test.png");
		const res = await app.request("/api/images", {
			method: "POST",
			body: formData,
		});
		expect(res.status).toBe(201);
		const json = await res.json();
		expect(json.filename).toMatch(/^\d+-[\w-]+\.png$/);
		expect(mockUploadImage).toHaveBeenCalledTimes(1);
	});
});
