import { mkdir, readdir, rename, rm, stat } from "node:fs/promises";
import path from "node:path";
import dotenv from "dotenv";
import { createClient } from "@supabase/supabase-js";
import {
  orphanUploadFolderName,
  type OrphanUploadIdentity
} from "../src/lib/orphan-upload-path";

dotenv.config({ path: ".env" });

function isWithin(root: string, candidate: string): boolean {
  const relative = path.relative(root, candidate);
  return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
}

function safePath(root: string, ...segments: string[]): string {
  const candidate = path.resolve(root, ...segments);
  if (!isWithin(root, candidate)) throw new Error("Unsafe upload path");
  return candidate;
}

function serverKeyIsValid(key: string): boolean {
  if (key.startsWith("sb_secret_")) return true;
  try {
    const payload = key.split(".")[1];
    if (!payload) return false;
    const claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8")) as { role?: string };
    return claims.role === "service_role";
  } catch {
    return false;
  }
}

async function exists(candidate: string): Promise<boolean> {
  try {
    await stat(candidate);
    return true;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
    throw error;
  }
}

async function main() {
  const projectId = process.env.SUPABASE_PROJECT_ID?.trim();
  const url =
    process.env.NEXT_PUBLIC_SUPABASE_URL?.trim() ||
    (projectId ? `https://${projectId}.supabase.co` : null);
  const key = process.env.SUPABASE_SECRET_KEY?.trim();
  if (!url || !key || !serverKeyIsValid(key)) {
    throw new Error("Set a valid Supabase URL and SUPABASE_SECRET_KEY before migrating uploads.");
  }

  const supabase = createClient(url, key, {
    auth: { autoRefreshToken: false, persistSession: false }
  });
  const { data: orphans, error } = await supabase
    .from("orphans")
    .select("id,full_name,case_number")
    .limit(10_000);
  if (error) throw new Error(error.message);

  const uploadRoot = path.resolve(process.cwd(), "public", "uploads");
  const orphanRoot = safePath(uploadRoot, "orphans");
  await mkdir(orphanRoot, { recursive: true });

  const totals = { moved: 0, named: 0, created: 0 };
  for (const orphan of orphans ?? []) {
    const identity: OrphanUploadIdentity = {
      orphanId: orphan.id,
      orphanName: orphan.full_name,
      caseNumber: orphan.case_number
    };
    const source = safePath(orphanRoot, orphan.id);
    const destination = safePath(orphanRoot, orphanUploadFolderName(identity));
    const sourceExists = await exists(source);
    const destinationExists = await exists(destination);

    if (sourceExists && destinationExists) {
      const destinationEntries = await readdir(destination);
      if (destinationEntries.length > 0) {
        throw new Error(`Both UUID and named folders contain data for ${identity.caseNumber}.`);
      }
      await rm(destination, { recursive: true });
    }

    if (sourceExists) {
      await rename(source, destination);
      totals.moved += 1;
    } else if (destinationExists) {
      totals.named += 1;
    } else {
      totals.created += 1;
    }

    await Promise.all([
      mkdir(safePath(destination, "documents"), { recursive: true }),
      mkdir(safePath(destination, "receipts"), { recursive: true })
    ]);
  }

  console.log(
    `Named orphan folders ready: ${totals.moved} moved, ${totals.named} already named, ${totals.created} created.`
  );
}

main().catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : "Orphan folder migration failed.");
  process.exitCode = 1;
});
