// @vitest-environment jsdom
import { act, useEffect, useSyncExternalStore } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";

const harness = vi.hoisted(() => {
  const listeners = new Set<() => void>();
  const appStateListeners = new Set<(state: string) => void>();
  const state = { focused: true, appState: "active" };
  return {
    state,
    appStateListeners,
    subscribe(listener: () => void) {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
    setFocused(focused: boolean) {
      state.focused = focused;
      for (const listener of listeners) listener();
    },
    setAppState(next: string) {
      state.appState = next;
      for (const listener of appStateListeners) listener(next);
    },
  };
});

vi.mock("@react-navigation/native", () => ({
  useIsFocused: () =>
    useSyncExternalStore(harness.subscribe, () => harness.state.focused),
}));
vi.mock("react-native", () => ({
  AppState: {
    get currentState() {
      return harness.state.appState;
    },
    addEventListener: (_event: "change", listener: (state: string) => void) => {
      harness.appStateListeners.add(listener);
      return { remove: () => harness.appStateListeners.delete(listener) };
    },
  },
}));

import { useVisibleSecondClock } from "./use-visible-second-clock";


import { useEffect as useEffectOld, useState } from "react";

// Verbatim timer logic from 3295b30 (WorkingTimer and ProviderSubagentBar).
function useOldWorkingTimer(): number {
  const [nowMs, setNowMs] = useState(() => Date.now());
  useEffectOld(() => {
    const intervalId = setInterval(() => setNowMs(Date.now()), 1_000);
    return () => clearInterval(intervalId);
  }, []);
  return nowMs;
}
function useOldSubagentBar(live: boolean): number {
  const [nowMs, setNowMs] = useState(() => Date.now());
  useEffectOld(() => {
    if (!live) return;
    const id = setInterval(() => setNowMs(Date.now()), 1_000);
    return () => clearInterval(id);
  }, [live]);
  return nowMs;
}

const START_MS = Date.UTC(2026, 9, 3, 12, 0, 0);
let commits = 0;
let wakeups = 0;
let lastValue = 0;
const impls = {
  "before:WorkingTimer": () => useOldWorkingTimer(),
  "before:ProviderSubagentBar(live)": () => useOldSubagentBar(true),
  "after:WorkingTimer": () => useVisibleSecondClock(true),
  "after:ProviderSubagentBar(live)": () => useVisibleSecondClock(true),
} as const;
type Impl = keyof typeof impls;
function Probe(props: { readonly impl: Impl }) {
  const v = impls[props.impl]();
  lastValue = v;
  useEffect(() => { commits += 1; });
  return null;
}
function step(ms: number) {
  for (let t = 0; t < ms; t += 1_000) act(() => { wakeups += vi.getTimerCount() > 0 ? 1 : 0; vi.advanceTimersByTime(1_000); });
}
const rows: string[] = [];
const scenarios = [
  ["visible (focused, active)", true, "active"],
  ["unfocused (retained route), active", false, "active"],
  ["focused, app background", true, "background"],
  ["focused, app inactive", true, "inactive"],
] as const;
describe("battery timers measurement", () => {
  for (const impl of Object.keys(impls) as Impl[]) {
    for (const [name, focused, appState] of scenarios) {
      it(`${impl} ${name}`, () => {
        vi.useFakeTimers(); vi.setSystemTime(START_MS);
        harness.state.focused = focused; harness.state.appState = appState;
        (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
        const root = createRoot(document.createElement("div"));
        act(() => root.render(<Probe impl={impl} />));
        commits = 0; wakeups = 0;
        step(60_000);
        rows.push(`${impl.padEnd(34)} | ${name.padEnd(36)} | armed-interval-seconds=${String(wakeups).padStart(2)} | commits/min=${String(commits).padStart(2)} | label-clock-at-end=+${(lastValue - START_MS) / 1000}s`);
        act(() => root.unmount());
        vi.useRealTimers();
      });
    }
  }
  it("resume: 10 min background then active", () => {
    for (const impl of ["before:WorkingTimer", "after:WorkingTimer"] as Impl[]) {
      vi.useFakeTimers(); vi.setSystemTime(START_MS);
      harness.state.focused = true; harness.state.appState = "active";
      const root = createRoot(document.createElement("div"));
      act(() => root.render(<Probe impl={impl} />));
      act(() => harness.setAppState("background"));
      commits = 0;
      step(600_000);
      const bg = commits;
      act(() => harness.setAppState("active"));
      rows.push(`${impl.padEnd(34)} | 600s background then active        | commits-in-background=${bg} | label-clock-immediately-after-resume=+${(lastValue - START_MS) / 1000}s (wall +600s)`);
      act(() => root.unmount());
      vi.useRealTimers();
    }
  });
  it("print", () => { require("node:fs").writeFileSync(process.env.MEASUREMENT_OUT ?? "measurement.txt", rows.join("\n") + "\n"); });
});
