// Exercise 2: optimistic message list with useActionState (harder)
//
// `ChatThread` should show a newly sent message immediately, marked as
// "sending", then have it replaced by the real (server-confirmed) message
// once `sendMessage` resolves — combining useOptimistic with
// useActionState, as covered in the theory's composition section.
//
// TODO 1: implement appendOptimisticMessage (pure, no hooks) — the updateFn
// TODO 2: implement sendMessageAction, matching useActionState's
//         (previousState, formData) => newState signature
// TODO 3: wire both hooks together in ChatThread

import { useActionState, useOptimistic } from "react";

interface Message {
  id: string;
  text: string;
  sending?: boolean;
}

async function sendMessage(text: string): Promise<Message> {
  await new Promise((resolve) => setTimeout(resolve, 500)); // simulated network delay
  return { id: `real-${text}`, text }; // server assigns the "real" id
}

// TODO 1: given the current list of messages and a new text payload, return
// a NEW array with an appended optimistic message: { id: `temp-${text}`,
// text, sending: true }. Do not mutate `current`.
function appendOptimisticMessage(current: Message[], text: string): Message[] {
  return current; // TODO: return [...current, { id: `temp-${text}`, text, sending: true }]
}

// TODO 2: signature must be (previousState: Message[], formData: FormData) => Promise<Message[]>.
// Read "text" off formData, call sendMessage, and return a NEW array with
// the confirmed message appended (no `sending` flag) to previousState.
async function sendMessageAction(previousState: Message[], formData: FormData): Promise<Message[]> {
  return previousState; // TODO: implement using sendMessage + appendOptimisticMessage's shape
}

function ChatThread() {
  // TODO 3:
  // const [messages, formAction] = useActionState(sendMessageAction, [] as Message[]);
  // const [optimisticMessages, addOptimisticMessage] = useOptimistic(messages, appendOptimisticMessage);
  const optimisticMessages: Message[] = [];
  const formAction = undefined as unknown as (formData: FormData) => void;

  return (
    <form
      action={async (formData: FormData) => {
        // TODO 3 (cont'd): call addOptimisticMessage(formData.get("text") as string)
        // BEFORE calling formAction(formData), so the optimistic entry shows
        // immediately while the real submission is still in flight.
        await formAction(formData);
      }}
    >
      <ul>
        {optimisticMessages.map((m) => (
          <li key={m.id} style={{ opacity: m.sending ? 0.5 : 1 }}>
            {m.text}
            {m.sending ? " (sending...)" : ""}
          </li>
        ))}
      </ul>
      <input name="text" />
      <button>Send</button>
    </form>
  );
}

export { ChatThread, sendMessageAction, appendOptimisticMessage, sendMessage };

// --- self-check: do not modify below this line ---
const before: Message[] = [{ id: "real-hi", text: "hi" }];
const after = appendOptimisticMessage(before, "bye");
const check1 =
  after.length === 2 &&
  after[1].id === "temp-bye" &&
  after[1].sending === true &&
  before.length === 1; // must not mutate the original array

console.log(check1 ? "PASS (appendOptimisticMessage)" : "FAIL (appendOptimisticMessage)");

// Verify visually: mount <ChatThread />, type a message and submit. The
// message should appear immediately at 50% opacity with "(sending...)",
// then within 500ms switch to full opacity with no "(sending...)" text,
// confirming the optimistic entry was replaced by the confirmed one.
