interface SourceRecord {
  objectKey: string;
  fileName: string;
  mimeType: string;
}

interface RangedObject {
  body: BodyInit | null;
  size: number;
  httpEtag?: string;
  httpMetadata?: { contentType?: string };
  range?: { offset?: number; length?: number; suffix?: number };
}

function parseRange(value: string | null): { offset: number; length?: number } | null | "invalid" {
  if (!value) return null;
  if (value.includes(",")) return "invalid";
  const match = /^bytes=(\d+)-(\d*)$/i.exec(value.trim());
  if (!match) return "invalid";
  const offset = Number(match[1]);
  const end = match[2] ? Number(match[2]) : undefined;
  if (!Number.isSafeInteger(offset) || offset < 0) return "invalid";
  if (end !== undefined && (!Number.isSafeInteger(end) || end < offset)) {
    return "invalid";
  }
  return end === undefined ? { offset } : { offset, length: end - offset + 1 };
}

function missing(): Response {
  return Response.json(
    { error: { code: "source_not_found", message: "找不到原始电子书。" } },
    { status: 404 },
  );
}

export function createBookSourceApi(dependencies: {
  findSource(bookId: string): Promise<SourceRecord | null>;
  getObject(
    key: string,
    range: { offset: number; length?: number } | null,
  ): Promise<RangedObject | null>;
}) {
  return {
    async get(request: Request, bookId: string): Promise<Response> {
      const source = await dependencies.findSource(bookId);
      if (!source) return missing();
      const range = parseRange(request.headers.get("range"));
      if (range === "invalid") {
        return new Response(null, {
          status: 416,
          headers: { "accept-ranges": "bytes" },
        });
      }
      const object = await dependencies.getObject(source.objectKey, range);
      if (!object) return missing();

      const headers = new Headers({
        "accept-ranges": "bytes",
        "cache-control": "private, no-store",
        "content-disposition": `inline; filename*=UTF-8''${encodeURIComponent(source.fileName)}`,
        "content-type": object.httpMetadata?.contentType || source.mimeType,
        etag: object.httpEtag ?? "",
      });
      const partial = Boolean(range && object.range);
      if (partial && object.range) {
        const length =
          object.range.length ??
          (object.range.offset !== undefined
            ? object.size - object.range.offset
            : object.range.suffix ?? object.size);
        const start =
          object.range.offset ?? Math.max(0, object.size - length);
        const end = start + length - 1;
        headers.set("content-range", `bytes ${start}-${end}/${object.size}`);
        headers.set("content-length", String(length));
      } else {
        headers.set("content-length", String(object.size));
      }
      return new Response(object.body, {
        status: partial ? 206 : 200,
        headers,
      });
    },
  };
}
