import { describe, expect, test } from "bun:test";

import {
  contentTypeFor,
  hasFileExtension,
  htmlResponse,
  serveStaticAsset,
  type StaticAssets,
} from "../../src/server/static";

function createTestAssets(): StaticAssets {
  return {
    files: {
      "/assets/index-a1b2c3.css": new Blob([".app{}"], { type: "text/css" }),
      "/assets/index-a1b2c3.js": new Blob(["console.log(1)"], { type: "text/javascript" }),
      "/assets/vendor-react-x9y8z7.js": new Blob(["react"], { type: "text/javascript" }),
      "/favicon.svg": new Blob(["<svg/>"], { type: "image/svg+xml" }),
    },
    indexHtml: new Blob(["<!doctype html><html></html>"], { type: "text/html" }),
  };
}

describe("contentTypeFor", () => {
  test("JavaScript 文件", () => {
    expect(contentTypeFor("/assets/index-a1b2c3.js")).toBe("text/javascript; charset=utf-8");
  });

  test("mjs 文件", () => {
    expect(contentTypeFor("/assets/chunk.mjs")).toBe("text/javascript; charset=utf-8");
  });

  test("CSS 文件", () => {
    expect(contentTypeFor("/assets/style.css")).toBe("text/css; charset=utf-8");
  });

  test("SVG 文件", () => {
    expect(contentTypeFor("/icon.svg")).toBe("image/svg+xml");
  });

  test("未知扩展名返回 octet-stream", () => {
    expect(contentTypeFor("/file.xyz")).toBe("application/octet-stream");
  });

  test("无扩展名返回 octet-stream", () => {
    expect(contentTypeFor("/noext")).toBe("application/octet-stream");
  });
});

describe("hasFileExtension", () => {
  test("有扩展名", () => {
    expect(hasFileExtension("/assets/index.js")).toBe(true);
    expect(hasFileExtension("/favicon.svg")).toBe(true);
  });

  test("无扩展名", () => {
    expect(hasFileExtension("/dashboard")).toBe(false);
    expect(hasFileExtension("/")).toBe(false);
    expect(hasFileExtension("/api/targets")).toBe(false);
  });
});

describe("htmlResponse", () => {
  test("返回 HTML 响应带正确 headers", async () => {
    const blob = new Blob(["<html></html>"]);
    const response = htmlResponse(blob);

    expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
    expect(response.headers.get("Cache-Control")).toBe("no-cache");
    expect(await response.text()).toBe("<html></html>");
  });
});

describe("serveStaticAsset", () => {
  test("根路径返回 indexHtml", async () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/", assets);

    expect(response.status).toBe(200);
    expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
    expect(response.headers.get("Cache-Control")).toBe("no-cache");
    expect(await response.text()).toBe("<!doctype html><html></html>");
  });

  test("已知资源返回对应文件和 immutable 缓存", async () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/assets/index-a1b2c3.js", assets);

    expect(response.status).toBe(200);
    expect(response.headers.get("Content-Type")).toBe("text/javascript; charset=utf-8");
    expect(response.headers.get("Cache-Control")).toBe("public, max-age=31536000, immutable");
    expect(await response.text()).toBe("console.log(1)");
  });

  test("未知带扩展名路径返回 404", () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/assets/missing.js", assets);

    expect(response.status).toBe(404);
  });

  test("SPA fallback — 无扩展名路径返回 indexHtml", async () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/dashboard", assets);

    expect(response.status).toBe(200);
    expect(response.headers.get("Content-Type")).toBe("text/html; charset=utf-8");
    expect(response.headers.get("Cache-Control")).toBe("no-cache");
    expect(await response.text()).toBe("<!doctype html><html></html>");
  });

  test("SVG 资源返回正确 Content-Type", () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/favicon.svg", assets);

    expect(response.status).toBe(200);
    expect(response.headers.get("Content-Type")).toBe("image/svg+xml");
    expect(response.headers.get("Cache-Control")).toBe("public, max-age=31536000, immutable");
  });

  test("CSS 资源返回正确 Content-Type", () => {
    const assets = createTestAssets();
    const response = serveStaticAsset("/assets/index-a1b2c3.css", assets);

    expect(response.status).toBe(200);
    expect(response.headers.get("Content-Type")).toBe("text/css; charset=utf-8");
  });
});
