import { useState } from "react";

import { toast } from "sonner";

import { Toaster } from "@/components/ui/sonner";

import { FeedbackIdeationA } from "./ideation-a";
import { MOCK_FEEDBACK } from "./mock-data";
import { FeedbackNewRequest } from "./new-request";
import type { FeedbackNewRequestPayload } from "./new-request";
import type { FeedbackCurrentUser, FeedbackItem, FeedbackRole } from "./types";

export interface FeedbackBoardProps {
  items?: FeedbackItem[];
  /**
   * Viewer role. Drives the filter set and the detail-drawer triage actions.
   * Creation is open to every role — only triage (approve/decline) is admin-only.
   */
  role?: FeedbackRole;
  /** Signed-in user — scopes the "My requests" filter. Defaults to the role's mock user. */
  currentUser?: FeedbackCurrentUser;
  /** Render the built-in page top bar. Pass `false` when a host supplies its own. */
  showTopBar?: boolean;
  /** Fires when the "Load more" button is pressed (host fetches the next page). */
  onLoadMore?: () => void;
  /** Whether more items can be loaded — shows the "Load more" button. */
  hasMore?: boolean;
  /** Whether a load-more fetch is in flight — disables the button. */
  isLoadingMore?: boolean;
  /** Controlled status filter. */
  status?: string;
  onStatusChange?: (value: string) => void;
  /** Controlled type filter. */
  type?: string;
  onTypeChange?: (value: string) => void;
  /** Controlled search query. */
  query?: string;
  onQueryChange?: (value: string) => void;
  /**
   * Fired when a new request is submitted — receives the full intake payload.
   * May return a promise: the drawer only closes, resets, and shows the success
   * toast once it resolves. If it rejects, the drawer stays open and `onError`
   * fires — the board never assumes the submission succeeded.
   */
  onSubmit?: (payload: FeedbackNewRequestPayload) => void | Promise<void>;
  /**
   * Fired when admin confirms approval. May return a promise — the detail
   * drawer stays open until it resolves and closes on success only; a rejection
   * fires `onError` and keeps the drawer open.
   */
  onApprove?: (item: FeedbackItem, priority: string) => void | Promise<void>;
  /**
   * Fired when admin clicks Decline. May return a promise — the detail drawer
   * stays open until it resolves and closes on success only; a rejection fires
   * `onError` and keeps the drawer open.
   */
  onDecline?: (item: FeedbackItem) => void | Promise<void>;
  /**
   * Fired when any async action (`onSubmit` / `onApprove` / `onDecline`)
   * rejects. The originating drawer stays open; the host decides how to surface
   * the failure (e.g. an error toast). The board shows no failure UI itself.
   */
  onError?: (error: unknown) => void;
  /** Fired when the upvote button is toggled. */
  onUpvote?: (item: FeedbackItem) => void;
}

/**
 * The complete back-office feedback page. An upvote board (Ideation A) wired to a
 * right-side intake form: both roles get the "New request" action. Submitting
 * forwards the payload via `onSubmit`; the form only closes, resets, and confirms
 * with a toast once the host resolves it. A rejected submission leaves the drawer
 * open and fires `onError` instead — the host owns failure feedback. Role drives
 * triage only — System Admin additionally gets approve / decline actions in the
 * detail drawer, which likewise close on success and fire `onError` on failure.
 */
export function FeedbackBoard({
  items = MOCK_FEEDBACK,
  role = "staff",
  currentUser,
  showTopBar = true,
  onLoadMore,
  hasMore = false,
  isLoadingMore = false,
  status,
  onStatusChange,
  type,
  onTypeChange,
  query,
  onQueryChange,
  onSubmit,
  onApprove,
  onDecline,
  onError,
  onUpvote,
}: FeedbackBoardProps) {
  const [newOpen, setNewOpen] = useState(false);
  // Remounts the form on each successful submit so the next request starts blank.
  const [formKey, setFormKey] = useState(0);

  return (
    <>
      <FeedbackIdeationA
        items={items}
        role={role}
        currentUser={currentUser}
        showTopBar={showTopBar}
        onNewRequest={() => setNewOpen(true)}
        onLoadMore={onLoadMore}
        hasMore={hasMore}
        isLoadingMore={isLoadingMore}
        status={status}
        onStatusChange={onStatusChange}
        type={type}
        onTypeChange={onTypeChange}
        query={query}
        onQueryChange={onQueryChange}
        onApprove={onApprove}
        onDecline={onDecline}
        onError={onError}
        onUpvote={onUpvote}
      />

      {/* Creation is open to every role — always mount the intake form. */}
      <FeedbackNewRequest
        key={formKey}
        open={newOpen}
        onOpenChange={setNewOpen}
        onSubmit={async (payload) => {
          // Await the host first. A rejection propagates to the form, which
          // fires onError and stays open — so we only reach the close + reset +
          // success toast when the submission actually succeeds.
          await onSubmit?.(payload);
          setNewOpen(false);
          setFormKey((k) => k + 1);
          toast.success("Request submitted", {
            description: "Thanks, your idea is now in the queue.",
          });
        }}
        onError={onError}
      />

      <Toaster position="bottom-right" />
    </>
  );
}
