// Exercise 2: don't block paint with expensive work
//
// `shouldBlockPaint` should model the timing fact from the theory: an effect
// registered with useLayoutEffect always runs before the next paint (so if
// it's slow, it blocks/delays that paint); an effect registered with
// useEffect never blocks the next paint (it runs after, asynchronously).
//
// Then classify each scenario in `SCENARIOS` as safe or risky based on
// which hook it uses and how expensive the work is.
//
// TODO 1: implement shouldBlockPaint(hookName)
// TODO 2: implement classifyScenario(hookName, estimatedMs)

import { useEffect, useLayoutEffect, useState } from "react";

type HookName = "useEffect" | "useLayoutEffect";

// TODO 1: pure function — does registering an effect with this hook mean
// the browser's next paint waits for it to finish?
function shouldBlockPaint(hookName: HookName): boolean {
  return false; // TODO: return hookName === "useLayoutEffect"
}

interface Scenario {
  name: string;
  hook: HookName;
  estimatedMs: number;
}

const SCENARIOS: Scenario[] = [
  { name: "measure tooltip position", hook: "useLayoutEffect", estimatedMs: 2 },
  { name: "sort 100k rows for a chart", hook: "useLayoutEffect", estimatedMs: 180 },
  { name: "fetch user profile", hook: "useEffect", estimatedMs: 300 },
  { name: "sync scroll position", hook: "useLayoutEffect", estimatedMs: 1 },
];

// TODO 2: a scenario is "risky" if it blocks paint (per shouldBlockPaint)
// AND its estimatedMs is over 16 (roughly one 60fps frame budget).
// Otherwise it's "safe". Return exactly "risky" or "safe".
function classifyScenario(hook: HookName, estimatedMs: number): "risky" | "safe" {
  return "safe"; // TODO: implement using shouldBlockPaint
}

// --- example component structure (illustrative, not required to run) ---
function ExpensiveMeasurement({ expensive }: { expensive: boolean }) {
  const [, forceRender] = useState(0);

  useLayoutEffect(() => {
    if (expensive) {
      // BAD: heavy synchronous work here blocks every paint
    }
  }, [expensive]);

  useEffect(() => {
    // GOOD: heavy work that doesn't need to finish before paint belongs here
  }, [expensive]);

  return null;
}

export { shouldBlockPaint, classifyScenario, SCENARIOS };

// --- self-check: do not modify below this line ---
const blockCheck = shouldBlockPaint("useLayoutEffect") === true && shouldBlockPaint("useEffect") === false;
console.log(blockCheck ? "PASS (shouldBlockPaint)" : "FAIL (shouldBlockPaint)");

const results = SCENARIOS.map((s) => classifyScenario(s.hook, s.estimatedMs));
const expected: Array<"risky" | "safe"> = ["safe", "risky", "safe", "safe"];
const classifyOk = JSON.stringify(results) === JSON.stringify(expected);
console.log(classifyOk ? "PASS (classifyScenario)" : "FAIL (classifyScenario)", results);

// Verify visually: in a real browser, open DevTools > Performance, record
// while mounting a component with an intentionally slow useLayoutEffect
// (e.g. a busy-wait loop) — you should see a long task blocking the first
// paint. Move the same work to useEffect and record again — paint happens
// immediately, the slow work shows up AFTER the paint frame instead.
