import "server-only";
import { ConvexError } from "convex/values";
import { AuthError, PermissionError } from "./auth";

export type ActionResult<T = undefined> = { ok: true; data: T } | { ok: false; error: string; code?: "AUTH" | "PERMISSION" | "CONFLICT" | "VALIDATION" | "NOT_FOUND" | "UNKNOWN"; fields?: Record<string, string>; conflicts?: unknown };

export class ActionError extends Error {
  constructor(message: string, public code: NonNullable<Extract<ActionResult, { ok: false }>["code"]> = "UNKNOWN") {
    super(message);
    this.name = "ActionError";
  }
}

/** Wrap a server action body so every failure returns a typed, user-safe result. */
export async function run<T>(fn: () => Promise<T>): Promise<ActionResult<T>> {
  try {
    const data = await fn();
    return { ok: true, data };
  } catch (e) {
    if (e instanceof ConvexError) {
      const d = (typeof e.data === "object" && e.data ? e.data : { message: String(e.data) }) as { code?: string; message?: string; fields?: Record<string, string>; conflicts?: unknown };
      const code = (["AUTH", "PERMISSION", "CONFLICT", "VALIDATION", "NOT_FOUND", "UNKNOWN"].includes(d.code ?? "") ? d.code : "UNKNOWN") as NonNullable<Extract<ActionResult, { ok: false }>["code"]>;
      return { ok: false, error: code === "AUTH" ? "Your session has expired. Please sign in again." : d.message ?? "Something went wrong.", code, fields: d.fields, conflicts: d.conflicts };
    }
    if (e instanceof AuthError) return { ok: false, error: "Your session has expired. Please sign in again.", code: "AUTH" };
    if (e instanceof PermissionError) return { ok: false, error: "You don't have permission to do this.", code: "PERMISSION" };
    if (e instanceof ActionError) return { ok: false, error: e.message, code: e.code };
    if (e && typeof e === "object" && "digest" in e && String((e as { digest: string }).digest).startsWith("NEXT_REDIRECT")) throw e;
    const msg = e instanceof Error ? e.message : String(e);
    if (/Unauthenticated|Not authenticated|token/i.test(msg)) return { ok: false, error: "Your session has expired. Please sign in again.", code: "AUTH" };
    console.error("[action]", e);
    return { ok: false, error: "Something went wrong. Please try again.", code: "UNKNOWN" };
  }
}
