import fs from "node:fs";
import path from "node:path";

// Load .env.local
const envPath = path.resolve(process.cwd(), ".env.local");
if (fs.existsSync(envPath)) {
  const raw = fs.readFileSync(envPath, "utf8");
  for (const line of raw.split("\n")) {
    const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
    if (!m) continue;
    let v = m[2].trim();
    if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
      v = v.slice(1, -1);
    }
    if (!(m[1] in process.env)) process.env[m[1]] = v;
  }
}

async function runTests() {
  console.log("============================================================");
  console.log("QUTO AI — SMART BLOG EDITOR & PUBLISHING ENGINE TEST SUITE");
  console.log("============================================================");

  // 1. Test Reading Time Calculation
  console.log("\n[TEST 1] Testing Reading Time Calculation...");
  const { calculateReadingStats } = await import("../lib/reading-time");
  const sample1 = "This is a short paragraph with exactly eight words.";
  const stats1 = calculateReadingStats(sample1);
  console.log(`- Sample 1: ${stats1.words} words -> ${stats1.readTime} (${stats1.minutes} min)`);
  if (stats1.words !== 9 || stats1.readTime !== "1 min read") {
    throw new Error(`Sample 1 calculation mismatch: got ${JSON.stringify(stats1)}`);
  }

  // 500 words
  const words500 = Array(500).fill("latency").join(" ");
  const stats500 = calculateReadingStats(words500);
  console.log(`- Sample 2 (500 words): ${stats500.words} words -> ${stats500.readTime}`);
  if (stats500.words !== 500 || stats500.readTime !== "3 min read") {
    throw new Error(`Sample 2 calculation mismatch: got ${JSON.stringify(stats500)}`);
  }
  console.log("✓ Reading Time calculation PASS");

  // 2. Test Authors Resolution
  console.log("\n[TEST 2] Testing Author System & Role Resolution...");
  const { getAuthorRoleLabel, resolveAuthorFromUser } = await import("../lib/admin/authors");
  const { db } = await import("../lib/admin/db");

  const mainAdminRole = getAuthorRoleLabel("MAIN_ADMIN", "MAIN_ADMIN");
  const editorRole = getAuthorRoleLabel("CONTENT_EDITOR", "SUB_ADMIN");
  console.log(`- Main Admin role mapped to: "${mainAdminRole}"`);
  console.log(`- Content Editor mapped to: "${editorRole}"`);

  if (mainAdminRole !== "Main Administrator" || editorRole !== "Blog / Content Editor") {
    throw new Error("Role mapping mismatch");
  }

  const users = await db.getUsers();
  console.log(`- Found ${users.length} registered admin user(s) in Atlas`);
  if (users.length === 0) throw new Error("No users found in Atlas database");

  const authorResolved = resolveAuthorFromUser(users[0]);
  console.log(`- Author 0 resolved: ${authorResolved.name} (${authorResolved.role}, ${authorResolved.avatarText})`);
  console.log("✓ Author System & Role Resolution PASS");

  // 3. Test Editorial Workflow: Draft -> Publish -> Working Draft Autosave -> Preview -> Update Live
  console.log("\n[TEST 3] Testing Critical Autosave & Versioning Separation...");
  const { blogService } = await import("../lib/blog-service");

  const mockAdmin = {
    id: users[0].id,
    name: users[0].name,
    email: users[0].email,
    role: users[0].role,
  };

  // Step 3a: Create a test draft
  const testTitle = `E2E Studio Test Post ${Date.now()}`;
  console.log(`- Creating draft: "${testTitle}"`);
  const post = await blogService.createDraft(
    {
      title: testTitle,
      category: "Voice AI Guides",
      authorId: users[0].id,
    },
    mockAdmin
  );
  console.log(`  Draft created with ID: ${post.id}, slug: ${post.slug}, author: ${post.author.name}`);

  // Step 3b: Publish the draft
  console.log(`- Publishing post (making it LIVE)...`);
  const publishedPost = await blogService.publish(
    post.id,
    mockAdmin
  );
  console.log(`  Status is now: ${publishedPost.status}, Live Slug: ${publishedPost.slug}`);

  // Verify public retrieval of live post
  const liveInitial = await blogService.getPostBySlug(publishedPost.slug);
  if (!liveInitial || liveInitial.id !== post.id) {
    throw new Error("Published post could not be retrieved publicly via getPostBySlug");
  }
  console.log("  Live post verified on public query by slug.");

  // Step 3c: AUTOSAVE changes to the published post (The Critical Requirement!)
  console.log("\n- Modifying published post with autosaved working draft changes...");
  const initialSlug = publishedPost.slug;
  const newWorkingSlug = `${initialSlug}-updated-working-draft`;
  const newWorkingTitle = `${testTitle} — WORKING DRAFT EDIT`;
  const newWorkingContent = "<p>This is uncommitted working draft content that must NOT appear live.</p>";

  const updatedDraftRes = await blogService.updateDraft(
    post.id,
    {
      title: newWorkingTitle,
      slug: newWorkingSlug,
      contentHtml: newWorkingContent,
      seoTitle: "Working SEO Title — Unpublished",
      metaDescription: "Working meta description that should not be visible publicly.",
    },
    mockAdmin
  );

  console.log(`  Autosave returned. hasWorkingDraft: ${updatedDraftRes.hasWorkingDraft}`);

  // Step 3d: VERIFY ISOLATION: The live public site MUST STILL SHOW THE ORIGINAL VERSION
  console.log("\n- Verifying PUBLIC SITE ISOLATION during working draft editing:");
  const liveAfterAutosave = await blogService.getPostBySlug(initialSlug);
  if (!liveAfterAutosave) {
    throw new Error("FAIL: Original live slug is not accessible!");
  }
  if (liveAfterAutosave.title !== testTitle) {
    throw new Error(`FAIL: Public live title was contaminated by autosave! Expected "${testTitle}", got "${liveAfterAutosave.title}"`);
  }
  if (liveAfterAutosave.slug !== initialSlug) {
    throw new Error(`FAIL: Public live slug changed before Update Live! Expected "${initialSlug}", got "${liveAfterAutosave.slug}"`);
  }

  // The new slug MUST NOT exist publicly
  const newSlugPublicCheck = await blogService.getPostBySlug(newWorkingSlug);
  if (newSlugPublicCheck !== null) {
    throw new Error("FAIL: Working draft new slug is prematurely live on public route!");
  }
  console.log("  ✓ Public live post remains 100% UNTOUCHED and shows original title and original slug.");
  console.log("  ✓ Working draft slug returns NULL on public query.");

  // Step 3e: VERIFY PREVIEW: Preview MUST show the working draft!
  console.log("\n- Verifying PREVIEW endpoint retrieves working draft changes:");
  const previewPost = await blogService.getPostForPreview(post.id);
  if (!previewPost) {
    throw new Error("FAIL: Preview post could not be retrieved");
  }
  if (previewPost.title !== newWorkingTitle) {
    throw new Error(`FAIL: Preview did not show working draft title! Expected "${newWorkingTitle}", got "${previewPost.title}"`);
  }
  if (previewPost.slug !== newWorkingSlug) {
    throw new Error(`FAIL: Preview did not show working draft slug! Expected "${newWorkingSlug}", got "${previewPost.slug}"`);
  }
  if (!previewPost.hasWorkingDraft) {
    throw new Error("FAIL: Preview did not indicate hasWorkingDraft: true");
  }
  console.log("  ✓ Preview displays uncommitted working draft title and slug perfectly.");

  // Step 3f: COMMIT VIA UPDATE LIVE
  console.log("\n- Admin clicks UPDATE LIVE (committing working draft to public)...");
  const liveCommit = await blogService.updateLive(
    post.id,
    mockAdmin
  );

  console.log(`  Update Live completed. Version: ${liveCommit.version}, hasWorkingDraft: ${liveCommit.hasWorkingDraft}`);
  if (liveCommit.title !== newWorkingTitle) {
    throw new Error(`FAIL: Update live did not commit working title. Expected "${newWorkingTitle}", got "${liveCommit.title}"`);
  }
  if (liveCommit.slug !== newWorkingSlug) {
    throw new Error(`FAIL: Update live did not commit working slug. Expected "${newWorkingSlug}", got "${liveCommit.slug}"`);
  }
  if (liveCommit.workingDraft !== null) {
    throw new Error("FAIL: workingDraft was not cleared after updateLive");
  }

  // Step 3g: Verify public site now reflects the new live version
  console.log("\n- Verifying public site after Update Live:");
  const newLivePost = await blogService.getPostBySlug(newWorkingSlug);
  if (!newLivePost || newLivePost.title !== newWorkingTitle) {
    throw new Error("FAIL: Public site does not return updated live post by new slug");
  }
  console.log("  ✓ New slug is now live on public website!");

  // Step 3h: Verify 301 redirect was created for the changed slug
  const redirects = await db.getRedirects();
  const foundRedirect = redirects.find((r) => r.source === `/blog/${initialSlug}`);
  if (!foundRedirect || foundRedirect.destination !== `/blog/${newWorkingSlug}`) {
    throw new Error(`FAIL: Automatic 301 redirect from /blog/${initialSlug} to /blog/${newWorkingSlug} was not created!`);
  }
  console.log(`  ✓ Automatic 301 redirect verified: ${foundRedirect.source} -> ${foundRedirect.destination} (HTTP ${foundRedirect.method || 301})`);

  // Step 3i: Clean up test post and redirect
  console.log("\n- Cleaning up test post & redirect from MongoDB...");
  const allPosts = await db.getPosts({ limit: 100 });
  for (const p of allPosts) {
    if (p.title.startsWith("E2E Studio Test Post")) {
      await db.updatePost(p.id, { status: "ARCHIVED" });
      await db.deletePost(p.id);
      console.log(`  - Cleaned up test post: ${p.id}`);
    }
  }
  if (foundRedirect) {
    await db.deleteRedirect(foundRedirect.id);
  }
  console.log("  ✓ Cleanup complete.");

  console.log("\n============================================================");
  console.log("ALL TESTS PASSED WITH 100% FIDELITY!");
  console.log("============================================================");
}

runTests().catch((err) => {
  console.error("\n❌ TEST SUITE FAILED:", err);
  process.exit(1);
});
