// Exercise 2: LikeButton's pending-state transitions (medium)
//
// Per theory section 3: a Server Action called outside a <form> (e.g.
// from an onClick handler) is typically wrapped in useTransition so the
// UI can reflect a pending state. This exercise isolates the PENDING
// STATE MACHINE as a pure reducer — the same shape useTransition drives
// internally, decoupled from React so it's deterministically testable.
//
// TODO 1: implement likeButtonReducer(state, event) where state shape is
// { liked: boolean; isPending: boolean; error: string | null } and event
// is one of:
//   { type: "CLICK" }             -> only valid when !isPending: set
//                                     isPending: true, clear error
//                                     (clicking while already pending is
//                                     a no-op — return state unchanged)
//   { type: "SUCCESS" }           -> isPending: false, liked: true, error: null
//   { type: "FAILURE"; error: string } -> isPending: false, error: <that
//                                          error>, liked UNCHANGED (the
//                                          optimistic-looking click did
//                                          NOT actually take effect)
//
// TODO 2: implement simulateLikeFlow(initialState, willSucceed, errorMessage)
// — a pure function modeling one full click-to-resolution cycle:
//   1. apply { type: "CLICK" } to initialState
//   2. if the result of step 1 shows isPending === false (meaning the
//      click was ignored because a request was already in flight),
//      return that state immediately — do not proceed further
//   3. otherwise, apply either { type: "SUCCESS" } (if willSucceed) or
//      { type: "FAILURE", error: errorMessage } to the step-1 result,
//      and return THAT final state

interface LikeState {
  liked: boolean;
  isPending: boolean;
  error: string | null;
}

type LikeEvent =
  | { type: "CLICK" }
  | { type: "SUCCESS" }
  | { type: "FAILURE"; error: string };

function likeButtonReducer(state: LikeState, event: LikeEvent): LikeState {
  // TODO: implement per the spec above
  return state;
}

function simulateLikeFlow(
  initialState: LikeState,
  willSucceed: boolean,
  errorMessage: string
): LikeState {
  // TODO: implement per the spec above
  return initialState;
}

export { likeButtonReducer, simulateLikeFlow };
export type { LikeState, LikeEvent };

// --- self-check: do not modify below this line ---
const checks: Array<[string, unknown, unknown]> = [];

const idle: LikeState = { liked: false, isPending: false, error: null };

const clicked = likeButtonReducer(idle, { type: "CLICK" });
checks.push(["CLICK from idle sets isPending", clicked.isPending, true]);
checks.push(["CLICK does not optimistically set liked", clicked.liked, false]);

const ignoredClick = likeButtonReducer(clicked, { type: "CLICK" });
checks.push(["a second CLICK while pending is a no-op (same reference)",
  ignoredClick === clicked, true]);

const succeeded = likeButtonReducer(clicked, { type: "SUCCESS" });
checks.push(["SUCCESS clears pending and sets liked", JSON.stringify(succeeded),
  JSON.stringify({ liked: true, isPending: false, error: null })]);

const failed = likeButtonReducer(clicked, { type: "FAILURE", error: "network error" });
checks.push(["FAILURE clears pending, sets error, leaves liked unchanged",
  JSON.stringify(failed), JSON.stringify({ liked: false, isPending: false, error: "network error" })]);

const successFlow = simulateLikeFlow(idle, true, "");
checks.push(["full success flow ends liked and not pending",
  JSON.stringify(successFlow), JSON.stringify({ liked: true, isPending: false, error: null })]);

const failureFlow = simulateLikeFlow(idle, false, "server down");
checks.push(["full failure flow ends with the error, not liked",
  JSON.stringify(failureFlow), JSON.stringify({ liked: false, isPending: false, error: "server down" })]);

const alreadyPendingFlow = simulateLikeFlow(clicked, true, "");
checks.push(["flow started while already pending short-circuits unresolved",
  JSON.stringify(alreadyPendingFlow), JSON.stringify(clicked)]);

let passed = 0;
for (const [label, actual, expected] of checks) {
  const ok = JSON.stringify(actual) === JSON.stringify(expected);
  passed += ok ? 1 : 0;
  console.log(`${ok ? "PASS" : "FAIL"}: ${label} (got ${JSON.stringify(actual)}, expected ${JSON.stringify(expected)})`);
}
console.log(passed === checks.length ? "PASS" : "FAIL");

// Verify visually: wire likeButtonReducer's transitions into a real
// LikeButton using useTransition + a Server Action per theory section 3,
// and confirm the button disables during isPending and shows the right
// end state after the (possibly artificially delayed) action resolves.
