"use client";

import { useEffect } from "react";
import { useFormStatus } from "react-dom";
import { toast } from "sonner";
import type { ProductUpdateState } from "../actions";

/**
 * Pieces every update panel repeats.
 *
 * They live here rather than in `actions.ts` because a `"use server"` module may
 * only export async functions — a shared constant or component there would break
 * the build.
 */

export const INITIAL_UPDATE_STATE: ProductUpdateState = {
  ok: false,
  message: null,
  errors: {},
};

export const inputClass =
  "w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none focus:ring-1 focus:ring-[#CC1414] disabled:bg-gray-50";

/** Shown when a panel has no rows to work with, in place of an empty table. */
export function EmptyPanel({ children }: { children: React.ReactNode }) {
  return (
    <p className="rounded-lg bg-amber-50 p-3 text-sm text-amber-800 ring-1 ring-amber-200">
      {children}
    </p>
  );
}

export function FieldError({ messages }: { messages?: string[] }) {
  if (!messages?.length) return null;
  return <p className="mt-1 text-xs text-red-600">{messages[0]}</p>;
}

export function Label({ children, required }: { children: React.ReactNode; required?: boolean }) {
  return (
    <label className="mb-1 block text-xs font-medium text-gray-700">
      {children}
      {required ? <span className="text-red-500"> *</span> : null}
    </label>
  );
}

/**
 * Nested inside the form on purpose: `useFormStatus` only reports on the form it
 * renders within, which is what gives the button its pending state without a
 * hand-managed boolean that could survive an early return.
 */
export function SubmitButton({ label = "Save changes" }: { label?: string }) {
  const { pending } = useFormStatus();

  return (
    <button
      type="submit"
      disabled={pending}
      className="rounded-lg bg-[#CC1414] px-5 py-2 text-sm font-medium text-white hover:bg-[#a30f0f] disabled:opacity-60"
    >
      {pending ? "Saving…" : label}
    </button>
  );
}

/**
 * Turns an action result into a toast, and closes the dialog once the save went
 * through. The panel itself stays declarative — it never has to decide when the
 * request finished.
 */
export function useUpdateResult(state: ProductUpdateState, onDone: () => void) {
  useEffect(() => {
    if (state.ok && state.message) {
      toast.success(state.message);
      onDone();
      return;
    }
    if (!state.ok && state.message) {
      toast.error(state.message);
    }
    // `onDone` is a stable callback from the panel; re-running on a new `state`
    // object is exactly the intent.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state]);
}

/** Any error the API reported that no field on this form owns. */
export function FormErrorSummary({ state, own }: { state: ProductUpdateState; own: string[] }) {
  const stray = Object.entries(state.errors)
    .filter(([key]) => !own.some((field) => key === field || key.startsWith(`${field}.`)))
    .flatMap(([, messages]) => messages);

  if (stray.length === 0) return null;

  return (
    <div className="rounded-lg bg-red-50 p-3 text-xs text-red-700 ring-1 ring-red-200">
      {stray.map((message, i) => (
        <p key={i}>{message}</p>
      ))}
    </div>
  );
}
