import { R2_SOFT_LIMIT_BYTES } from "../../domain/storage.ts";
import type { D1DatabaseLike } from "../d1.ts";

interface UsageRow {
  used_bytes: number;
  source_bytes: number;
  audio_bytes: number;
  pending_upload_bytes: number;
}

export class StorageRepository {
  private readonly database: D1DatabaseLike;

  constructor(database: D1DatabaseLike) {
    this.database = database;
  }

  async usage() {
    const row = await this.database.prepare(`
      SELECT
        COALESCE(SUM(bytes), 0) AS used_bytes,
        COALESCE(SUM(CASE WHEN kind = 'source' THEN bytes ELSE 0 END), 0) AS source_bytes,
        COALESCE(SUM(CASE WHEN kind = 'audio' THEN bytes ELSE 0 END), 0) AS audio_bytes,
        COALESCE((
          SELECT SUM(total_bytes)
          FROM upload_sessions
          WHERE status IN ('created', 'uploading', 'completing')
        ), 0) AS pending_upload_bytes
      FROM storage_ledger
    `).first<UsageRow>();
    return {
      usedBytes: Number(row?.used_bytes ?? 0),
      sourceBytes: Number(row?.source_bytes ?? 0),
      audioBytes: Number(row?.audio_bytes ?? 0),
      pendingUploadBytes: Number(row?.pending_upload_bytes ?? 0),
      softLimitBytes: R2_SOFT_LIMIT_BYTES,
    };
  }

  async assertSourceAdmission(bytes: number): Promise<void> {
    return this.assertAdmission(bytes);
  }

  async assertAdmission(bytes: number, reclaimableBytes = 0): Promise<void> {
    if (!Number.isInteger(bytes) || bytes < 1) throw new Error("文件大小格式不正确。");
    const current = await this.usage();
    if (
      current.usedBytes + current.pendingUploadBytes - Math.max(0, reclaimableBytes) + bytes >
      R2_SOFT_LIMIT_BYTES
    ) {
      throw new Error("云端存储空间接近 8 GB 上限，请先删除不需要的书籍。");
    }
  }
}
