// Exercise 1: typed context + a custom hook that throws outside its provider
//
// Implement ThemeContext, ThemeProvider, and useTheme so that:
//   - ThemeContext is typed as `Theme | undefined`, default `undefined`
//   - useTheme() returns the current Theme when called inside a ThemeProvider
//   - useTheme() THROWS a descriptive Error when called outside one
//
// Then fix the bug in `BrokenApp`: it renders <ThemedLabel /> WITHOUT
// wrapping it in <ThemeProvider>, which should throw when useTheme runs.
// `FixedApp` should wrap it correctly and render without throwing.
//
// TODO 1: type ThemeContext as React.Context<Theme | undefined>
// TODO 2: implement useTheme() with the throw-if-undefined check
// TODO 3: fix FixedApp to wrap <ThemedLabel /> in <ThemeProvider>

import { createContext, useContext, useState } from "react";

type Theme = "light" | "dark";

// TODO 1: createContext<Theme | undefined>(undefined)
const ThemeContext = createContext<Theme>("light" as Theme); // BUG: wrong default pattern

function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme] = useState<Theme>("dark");
  return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
}

// TODO 2: throw if ctx is undefined; return ctx otherwise
function useTheme(): Theme {
  const ctx = useContext(ThemeContext);
  return ctx; // TODO: add the undefined check + throw
}

function ThemedLabel() {
  const theme = useTheme();
  return <span>current theme: {theme}</span>;
}

function BrokenApp() {
  return <ThemedLabel />; // no ThemeProvider — useTheme should throw
}

// TODO 3: wrap ThemedLabel in ThemeProvider
function FixedApp() {
  return <ThemedLabel />; // TODO: wrap this in <ThemeProvider>...</ThemeProvider>
}

export { ThemeContext, ThemeProvider, useTheme, ThemedLabel, BrokenApp, FixedApp };

// --- self-check: do not modify below this line ---
// Pure logic check: useTheme's throw behavior can be tested by calling the
// hook's underlying logic outside of React's render (simulate via a plain
// function mirroring the check, since hooks can't be called outside components):
function simulateUseTheme(ctxValue: Theme | undefined): Theme {
  if (ctxValue === undefined) throw new Error("useTheme must be used within a ThemeProvider");
  return ctxValue;
}

let threw = false;
try {
  simulateUseTheme(undefined);
} catch {
  threw = true;
}
console.log(threw ? "PASS (throws without provider)" : "FAIL (throws without provider)");
console.log(simulateUseTheme("dark") === "dark" ? "PASS (returns value with provider)" : "FAIL (returns value with provider)");

// Verify visually: render <BrokenApp /> — it should throw/crash (an error
// boundary or the console will show "useTheme must be used within a
// ThemeProvider"). Render <FixedApp /> — it should render
// "current theme: dark" with no error.
