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

const reactorApi: ApiSection[] = [
  {
    title: 'Chemical.Reactor',
    description: 'A Reactor is a server-side factory for creating and managing `Reaction` objects. Reactions are stateful objects whose state is automatically replicated from the server to specified clients.',
    entries: [
      {
        signature: 'Chemical.Reactor<T, U...>(config: ReactorConfig, constructor: (key: string, ...args: U) => T): ReactorInstance<T, U>',
        description: 'Creates a new Reactor factory.',
        parameters: [
          { name: 'config', type: 'ReactorConfig', description: 'Configuration for the Reactor. Must include a unique `Name`. Optionally, `Subjects` can specify which players receive updates (defaults to all players).' },
          { name: 'constructor', type: '(key: string, ...args: U) => T', description: "A function that returns the initial state structure for a new Reaction. This function receives the `key` of the Reaction (e.g., a player's ID) and any additional arguments passed to `reactor:create()`. The provided `key` is primarily for the Reactor system's internal identification and typically does not need to be stored as a field in the state object returned by this constructor, as the Reaction instance will have `.Name` and `.Key` properties managed by Chemical." },
        ],
        returns: { type: 'ReactorInstance<T, U>', description: 'A new Reactor instance.' },
        notes: 'ReactorConfig: `{ Name: string, Subjects?: Player[] | Symbol }`. The `Symbol` can be `Chemical.Symbols.All("Players")`. `T` is the type of the state structure returned by the constructor. `U...` are the types of additional arguments for the constructor.',
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value
local Table = Chemical.Table
local Reactor = Chemical.Reactor
local Symbols = Chemical.Symbols

-- Define a Reactor for player game data
local PlayerGameDataReactor = Reactor({
  Name = "PlayerGameData",
  -- Subjects = {player1, player2} -- Optional: replicate only to specific players
  -- Subjects = Symbols.All("Players") -- Default: replicate to all
}, function(playerIdString, initialLives, initialScore)
  -- This constructor defines the structure of each Reaction.
  -- Note: 'playerIdString' (the key) is passed here but typically
  -- not stored directly in this returned table, as the Reaction object
  -- will have .Key and .Name properties managed by Chemical.
  return {
    lives = Value(initialLives or 3),
    score = Value(initialScore or 0),
    inventory = Table({})
  }
end)
        `,
      },
    ],
  },
  {
    title: 'ReactorInstance Methods',
    entries: [
      {
        signature: 'reactor:create(key: string, ...args: U): Reaction<T>  -- Server-Only',
        description: 'Creates a new `Reaction` instance managed by this Reactor. The Reaction\'s state will be initialized using the constructor function provided when the Reactor was defined. This method can only be called on the server.',
        parameters: [
          { name: 'key', type: 'string', description: 'A unique key to identify this Reaction instance (e.g., a player\'s UserId).' },
          { name: '...args', type: 'U', description: 'Additional arguments to pass to the Reaction\'s constructor function.' },
        ],
        returns: { type: 'Reaction<T>', description: 'The newly created (and replicating) Reaction object.' },
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Value = Chemical.Value -- Assuming Value is used in constructor
local Table = Chemical.Table -- Assuming Table is used in constructor
-- Assuming PlayerGameDataReactor is defined as in the previous example

-- Server-side:
local player1Data = PlayerGameDataReactor:create("player1_id", 5, 1000)
-- player1Data.lives:get() would be 5
-- player1Data.score:get() would be 1000

player1Data.score:set(1500) -- Access directly; this change will be replicated.
player1Data.inventory:insert("Sword") -- Access directly
        `,
      },
      {
        signature: 'reactor:await(key: string): Reaction<T>  -- Client-Only',
        description: 'Yields (waits) until a `Reaction` instance, created on the server and managed by this Reactor, becomes available on the client. It then returns the Reaction object directly.',
        parameters: [
          { name: 'key', type: 'string', description: 'The unique key of the Reaction instance to await.' },
        ],
        returns: { type: 'Reaction<T>', description: 'The Reaction object, once available.' },
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
local Effect = Chemical.Effect
-- Assuming PlayerGameDataReactor is defined and available on the client
-- and its constructor creates { lives = Value(), score = Value(), inventory = Table() }

-- Client-side:
local player1Data = PlayerGameDataReactor:await("player1_id") -- Yields until data is ready

-- Now player1Data is the actual Reaction object
if player1Data then
  print("Player 1 score:", player1Data.score:get())

  Effect(function()
    print("Player 1 lives updated to:", player1Data.lives:get())
    print("Player 1 inventory count:", #player1Data.inventory:get())
  end)
else
  warn("Failed to get player data for player1_id")
end
        `,
      },
      {
        signature: 'reactor:onCreate(callback: (key: string, reaction: Reaction<T>) -> ()): Connection  -- Client-Only',
        description: 'Registers a callback function that will be invoked whenever a new `Reaction` instance managed by this Reactor is created and replicated to the client. This is useful for reacting to dynamically created Reactions.',
        parameters: [
          { name: 'callback', type: '(key: string, reaction: Reaction<T>) -> ()', description: 'The function to call. It receives the `key` of the new Reaction and the Reaction object itself.' },
        ],
        returns: { type: 'Connection', description: 'A connection object with a `:Disconnect()` method to stop listening.' },
        example: `
local Chemical = require(game.ReplicatedStorage.Chemical)
-- Assuming PlayerGameDataReactor is defined and available on the client

-- Client-side:
local connection = PlayerGameDataReactor:onCreate(function(playerId, playerData)
  print("New player data received for:", playerId)
  -- Access properties directly:
  -- print("Initial score for new player:", playerData.score:get())
end)

-- To stop listening:
-- connection:Disconnect()
        `,
      },
    ],
  },
];

export const ReactorPage: React.FC = () => {
  return <ContentPage title="Chemical.Reactor" sections={reactorApi} />;
};
