const assert = require("assert");
const fs = require("fs");
const path = require("path");

const root = path.join(__dirname, "..");
const sandbox = fs.mkdtempSync(path.join(root, ".tmp-lumi-content-library-"));
const serviceDir = path.join(sandbox, "src", "services");
fs.mkdirSync(serviceDir, { recursive: true });

for (const file of [
  "config.js",
  "db.js",
  "settings.js",
  "upload-security.js",
  "content-library.js",
  "content-routes.js"
]) {
  fs.copyFileSync(path.join(root, "src", "services", file), path.join(serviceDir, file));
}

let database = null;
(async () => {
  try {
    database = require(path.join(serviceDir, "db.js"));
    // Core imports the Web server before main() runs migrate(). The content
    // service must therefore be safe to load without touching database tables.
    const library = require(path.join(serviceDir, "content-library.js"));
    const routes = require(path.join(serviceDir, "content-routes.js"));
    database.migrate();
    const settings = require(path.join(serviceDir, "settings.js"));
    settings.ensureDefaults();
    settings.setSetting("session_secret", "content-library-verification-secret");
    assert(database.db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'content_resources'").get());
    library.ensureContentLibrary();
    assert(library.supportedExtensions().includes(".mp4"));
    assert(library.supportedExtensions().includes(".mp3"));
    assert(library.supportedExtensions().includes(".webm"));
    assert(library.supportedExtensions().includes(".png"));
    assert(library.supportedExtensions().includes(".woff2"));

    const pngPath = path.join(library.INCOMING_DIR, "verify.png.upload");
    fs.writeFileSync(
      pngPath,
      Buffer.from(
        "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9ZK1sAAAAASUVORK5CYII=",
        "base64"
      )
    );
    const [created] = await library.importUploadedFiles([
      {
        path: pngPath,
        originalname: "Alert Graphic.png",
        mimetype: "image/png"
      }
    ], { access_level: "locked", uploaded_by: "verify-admin" });

    assert.strictEqual(created.access_level, "locked");
    assert.strictEqual(created.category, "image");
    assert.strictEqual(created.preview_kind, "image");
    assert.strictEqual(library.publicUrl(created, "https://lumi.example"), null);
    assert(fs.existsSync(library.resourceFilePath(created)));
    assert.match(library.serializeResource(created, { base_url: "https://lumi.example" }).download_url, /\/admin\/resources\/[^/]+\/download\/Alert%20Graphic\.png$/);

    const signed = new URL(library.createSignedUrl(created.id, {
      base_url: "https://lumi.example",
      ttl_seconds: 60
    }));
    const signedResource = library.verifySignedResource(
      created.id,
      signed.searchParams.get("expires"),
      signed.searchParams.get("sig")
    );
    assert.strictEqual(signedResource.id, created.id);

    const exposed = library.setResourceAccess(created.id, "exposed");
    const publicUrl = new URL(library.publicUrl(exposed, "https://lumi.example"));
    const publicToken = publicUrl.pathname.split("/")[2];
    assert(publicToken.length >= 40);
    assert.strictEqual(library.getResourceByExposedToken(publicToken).id, created.id);

    const renamed = library.updateResourceName(created.id, "Follower alert");
    assert.strictEqual(renamed.display_name, "Follower alert");
    assert.strictEqual(library.listResources({ category: "image" }).length, 1);

    assert.deepStrictEqual(routes.parseByteRange("bytes=0-9", 100), { start: 0, end: 9 });
    assert.deepStrictEqual(routes.parseByteRange("bytes=-10", 100), { start: 90, end: 99 });
    assert.strictEqual(routes.parseByteRange("bytes=200-300", 100).invalid, true);
    assert.strictEqual(routes.parseByteRange("bytes=0-1,4-5", 100).invalid, true);

    const stats = library.getStorageStats();
    assert.strictEqual(stats.file_count, 1);
    assert(stats.used_bytes > 0);
    assert(stats.max_file_bytes > 0);

    const configuredStorage = library.updateStorageSettings({
      limit_gib: "2.5",
      reserve_gib: "0.25",
      max_file_mib: "32",
      max_files: "7"
    });
    assert.strictEqual(configuredStorage.limit_bytes, Math.floor(2.5 * 1024 ** 3));
    assert.strictEqual(configuredStorage.reserve_bytes, Math.floor(0.25 * 1024 ** 3));
    assert.strictEqual(configuredStorage.max_file_bytes, 32 * 1024 ** 2);
    assert.strictEqual(configuredStorage.max_files, 7);
    assert.deepStrictEqual(library.uploadLimits(), { max_file_bytes: 32 * 1024 ** 2, max_files: 7 });
    assert.throws(
      () => library.updateStorageSettings({}),
      /Complete every storage-limit field before saving/
    );
    assert.throws(
      () => library.updateStorageSettings({
        limit_gib: "2.5",
        reserve_gib: "-1",
        max_file_mib: "32",
        max_files: "7"
      }),
      /Storage values must be positive numbers/
    );
    assert.deepStrictEqual(library.uploadLimits(), { max_file_bytes: 32 * 1024 ** 2, max_files: 7 });

    const lockedAgain = library.setResourceAccess(created.id, "locked");
    assert.strictEqual(library.getResourceByExposedToken(publicToken), null);
    assert.strictEqual(lockedAgain.public_token, "");

    const storedPath = library.resourceFilePath(created);
    library.deleteResource(created.id);
    assert.strictEqual(fs.existsSync(storedPath), false);
    assert.strictEqual(library.getResource(created.id), null);
    assert.strictEqual(library.getStorageStats().file_count, 0);

    const serverSource = fs.readFileSync(path.join(root, "src", "web", "server.js"), "utf8");
    assert(serverSource.includes("registerPublicContentRoutes(app)"));
    assert(serverSource.includes("registerContentAdminRoutes(app"));
    assert(serverSource.includes('path: "/admin/resources"'));
    assert(serverSource.includes("global.lumiFrameworks.resources"));

    const overlayRouteSource = fs.readFileSync(path.join(root, "src", "services", "overlay-routes.js"), "utf8");
    assert(overlayRouteSource.includes("media-src https: http: data: blob:"), "OBS overlay CSP must allow configured media sources");

    const viewSource = fs.readFileSync(path.join(root, "src", "web", "views", "admin-resources.ejs"), "utf8");
    assert(viewSource.includes("data-resource-dropzone"));
    assert(viewSource.includes("data-resource-preview-modal"));
    assert(viewSource.includes("data-resource-media-toggle") && viewSource.includes("data-resource-media-seek"));
    assert(viewSource.includes("data-resource-rename-submit") && viewSource.includes("resource-more-actions"));
    assert(viewSource.includes("Available to Lumi"));
    assert(viewSource.includes("data-resource-access-form") && viewSource.includes("data-confirm-mode=\"modal\"") && viewSource.includes("data-no-destructive-confirm"));
    assert(viewSource.includes("data-resource-settings-summary"));
    for (const field of ["limit_gib", "reserve_gib", "max_file_mib", "max_files"]) {
      assert(new RegExp(`name="${field}"[^\\n]*required`).test(viewSource));
    }
    const contentRouteSource = fs.readFileSync(path.join(root, "src", "services", "content-routes.js"), "utf8");
    assert(contentRouteSource.includes('/admin/resources/:id/revoke'));
    assert(contentRouteSource.includes('/admin/resources/:id/download/:filename'));

    const clientSource = fs.readFileSync(path.join(root, "src", "web", "public", "content-library.js"), "utf8");
    assert(clientSource.includes("window.LumiConfirm?.destructiveToken"), "Resource actions must use the shared timed confirmation API");
    assert(clientSource.includes('headers["X-Confirmation-Token"] = token'), "Resource actions must send the issued confirmation token directly");
    assert(clientSource.includes("data-resource-upload-limit-copy") && clientSource.includes("selectedFilesError"), "Saved upload limits must be reflected and enforced in the UI");
    assert(clientSource.includes('"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"'));
    assert(clientSource.includes("const body = new URLSearchParams()"), "Resource action forms must use an encoding Express parses without upload middleware");

    const cssSource = fs.readFileSync(path.join(root, "src", "web", "public", "content-library.css"), "utf8");
    assert(cssSource.includes(".resource-empty-state[hidden]") && cssSource.includes("display: none !important"));
    assert(cssSource.includes(".resource-preview-tile:focus-within .resource-media-controls"));

    const coreKnowledge = fs.readFileSync(path.join(root, "knowledge", "core", "lumi-core.md"), "utf8");
    assert(coreKnowledge.includes("GET /admin/resources") && coreKnowledge.includes("GET /media/:token/:filename"));

    console.log("Content-library verification passed.");
  } finally {
    try { database?.db?.close(); } catch {}
    fs.rmSync(sandbox, { recursive: true, force: true });
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
