"use client";

/**
 * Form gắn thẳng vào server action nhưng có phản hồi cho người dùng:
 *  - hỏi xác nhận trước khi chạy (prop `confirm`, dùng cho thao tác xoá/huỷ);
 *  - khoá nút bấm khi đang xử lý để không bấm đúp;
 *  - báo "Đã lưu…" khi xong, hoặc báo lỗi thay vì màn hình "Application error".
 *
 * Server action có thể trả về `{ ok }`, `{ info }` hoặc `{ error }` để tự quyết định nội dung
 * thông báo; không trả gì thì dùng `success`. Action gọi `redirect()` vẫn chuyển trang bình thường.
 */
import { useTransition, type FormEvent, type FormHTMLAttributes, type ReactNode } from "react";
import { flashToast, useToast } from "./toast";

const GENERIC_ERROR = "Không thực hiện được. Dữ liệu có thể đã thay đổi — hãy tải lại trang rồi thử lại.";

function errorMessage(err: unknown): string {
  const raw = err instanceof Error ? err.message : "";
  if (raw === "UNAUTHENTICATED") return "Phiên đăng nhập đã hết hạn. Hãy đăng nhập lại.";
  // Bản production giấu nội dung lỗi của server action bằng câu tiếng Anh chung chung.
  if (!raw || /omitted in production|Server Components render/i.test(raw)) return GENERIC_ERROR;
  return raw;
}

function isRedirect(err: unknown): boolean {
  const digest = (err as { digest?: unknown } | null)?.digest;
  return typeof digest === "string" && digest.startsWith("NEXT_REDIRECT");
}

type Props = Omit<FormHTMLAttributes<HTMLFormElement>, "action" | "onSubmit"> & {
  action: (formData: FormData) => unknown;
  /** Nội dung thông báo khi thành công. */
  success?: string;
  /** Có giá trị thì hỏi xác nhận trước khi chạy. */
  confirm?: string;
  /** Xoá trắng ô nhập sau khi thành công (dùng cho form thêm mới). */
  resetOnSuccess?: boolean;
  /** Action kết thúc bằng redirect() — thông báo sẽ hiện ở trang đích thay vì ở trang này. */
  redirects?: boolean;
  children: ReactNode;
};

export function ActionForm({ action, success = "Đã lưu.", confirm, resetOnSuccess, redirects, children, ...rest }: Props) {
  const [pending, startTransition] = useTransition();
  const toast = useToast();

  function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (pending) return;
    if (confirm && !window.confirm(confirm)) return;

    const form = event.currentTarget;
    // Kèm nút đã bấm để action đọc được name/value của nó (VD duyệt / từ chối).
    const submitter = (event.nativeEvent as SubmitEvent).submitter as HTMLElement | null;
    const formData = new FormData(form, submitter);

    startTransition(async () => {
      if (redirects) flashToast.set(success);
      try {
        const result = (await action(formData)) as { ok?: string; info?: string; error?: string } | null | undefined;
        if (redirects) flashToast.clear();
        if (result && typeof result === "object" && result.error) {
          toast.error(result.error);
          return;
        }
        if (result && typeof result === "object" && result.info) {
          toast.info(result.info);
          return;
        }
        toast.success((result && typeof result === "object" && result.ok) || success);
        if (resetOnSuccess) form.reset();
      } catch (err) {
        if (isRedirect(err)) throw err;
        if (redirects) flashToast.clear();
        toast.error(errorMessage(err));
      }
    });
  }

  return (
    <form {...rest} onSubmit={onSubmit} data-pending={pending ? "true" : undefined}>
      {children}
    </form>
  );
}
