
import React from 'react';
import { ContentPage } from '../../components/ContentPage';
import { InfoPanel } from '../../components/InfoPanel';
import { ApiSection } from '../../types';

const effectApi: ApiSection[] = [
  {
    title: 'Chemical.Effect',
    description: 'Creates a side effect that runs after a batch of state changes has been processed and all dependent Computeds have been updated. Effects are used for interacting with the outside world, like updating UI, making network calls, or logging. They automatically re-run when their dependencies change.',
    entries: [
      {
        signature: 'Chemical.Effect(effectFn: () => CleanUpFunction | ()): Effect',
        description: 'Constructs a new Effect.',
        parameters: [
          { name: 'effectFn', type: '() => CleanUpFunction | ()', description: 'A function that performs the side effect. Any reactive objects accessed via `:get()` inside this function become dependencies. This function can optionally return a `CleanUpFunction`.' },
        ],
        returns: { type: 'Effect', description: 'A new Effect object.' },
        notes: '`CleanUpFunction`: A function of type `() -> ()` that is called before the `effectFn` re-runs due to dependency changes, or when the Effect is destroyed.',
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect

local name = Value("User")
local counter = Value(0)

local loggingEffect = Effect(function()
  -- This effect depends on 'name' and 'counter'
  local currentName = name:get()
  local currentCount = counter:get()
  print("Effect triggered: Name is " .. currentName .. ", Count is " .. currentCount)

  -- Optional cleanup function
  return function()
    print("Cleaning up effect for Name: " .. currentName .. ", Count: " .. currentCount)
  end
end)

name:set("Admin")     -- Effect re-runs (cleanup for "User", 0 runs first)
counter:set(5)      -- Effect re-runs (cleanup for "Admin", 0 runs first)
-- Note: If both set calls happen in the same frame, the effect might only run once
-- with ("Admin", 5), after the cleanup for ("User", 0) or ("Admin",0) depending on intermediate states.
        `,
      },
    ],
  },
  {
    title: 'Effect Methods',
    entries: [
      {
        signature: 'effect:destroy()',
        description: 'Destroys the Effect object. If the `effectFn` returned a cleanup function, it will be called. This also removes its dependencies on other reactive objects.',
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect

local isActive = Value(true)
local myEffect = Effect(function()
  if isActive:get() then
    print("Effect is active")
    return function() print("Effect cleaning up: was active") end
  else
    print("Effect is inactive")
    return function() print("Effect cleaning up: was inactive") end
  end
end)

isActive:set(false) -- Effect re-runs
myEffect:destroy()  -- The last cleanup function ("Effect cleaning up: was inactive") runs.
        `,
      },
      {
        signature: 'effect:clean()',
        description: 'Explicitly runs the cleanup function returned by the last execution of `effectFn`, if one exists. This is typically managed internally by the scheduler or when the effect is destroyed, but can be called manually.',
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Effect = Chemical.Effect

local data = Value("initial")
local effectWithCleanup = Effect(function()
  local currentData = data:get()
  print("Processing:", currentData)
  return function() print("Cleaning up for:", currentData) end
end)

data:set("updated") -- Effect re-runs, cleanup for "initial" runs.
effectWithCleanup:clean() -- Cleanup for "updated" runs.
        `,
         notes: "This method is less commonly used directly. Destruction usually handles cleanup.",
      },
    ],
  },
];

export const EffectPage: React.FC = () => {
  return (
    <ContentPage title="Chemical.Effect" sections={effectApi}>
      <InfoPanel type="note" title="Execution Timing & Batching">
        <p>
          Effects are batched and run by the Chemical scheduler. This typically happens at the
          end of the current frame or scheduler tick, <strong>after</strong> all direct state changes
          (e.g., from <code>:set()</code> on a Value) and <code>Computed</code> value updates for that tick
          have been processed.
        </p>
        <p className="mt-2">
          If an Effect's dependencies change multiple times within a single frame, the Effect
          will only run <strong>once</strong>, reacting to the <strong>most recent (final) state</strong> of its
          dependencies for that frame.
        </p>
        <p className="mt-2">
          The <code>CleanUpFunction</code> (if returned by the <code>effectFn</code>) is called before the
          <code>effectFn</code> re-runs due to dependency changes, or when the Effect is destroyed.
        </p>
      </InfoPanel>
    </ContentPage>
  );
};
