/** @module API/Common */

/**
 * Symbol identifier as used in responses (e.g., "0"..."11").
 */
export type SymbolId = string;

/**
 * API version string. Slots currently use "2".
 */
export type ApiVer = "1" | "2" | string;

/**
 * Monetary value expressed in subunits (minor units).
 * Example: with exponent=2, value 100 represents 1.00.
 */
export type Money = number;

/**
 * Current flow/state of the game round.
 */
export type FlowState = "ready" | "closed" | "freespins" | "respins" | string;

/**
 * Command sent to or reflected by the backend.
 */
export type FlowCommand = "init" | "spin" | "freespin" | "respin" | string;

/**
 * Known purchasable feature names; extensible for game‑specific features.
 */
export type FeatureName = "freespin_buy" | "bonus_buy" | "bonus_chance" | string;

/**
 * Symbol type/category. `default` is used for standard paytable.
 */
export type SymbolType = "default" | "wild" | "scatter" | string;

/**
 * Payouts for a single symbol across match counts, e.g. [0,0,30,50,100].
 * Index positions correspond to symbol count positions defined by the game.
 */
export type SymbolPayouts = Money[];

/**
 * Primary paytable: mapping symbol id -> payouts for that symbol.
 */
export type Paytable = Record<SymbolId, SymbolPayouts>;

/**
 * Paytable variants for a single symbol (default/wild/scatter or custom keys).
 * All keys are optional to allow partial presence per symbol.
 */
export type PaytableVariants = Record<SymbolType, SymbolPayouts | undefined>;

/**
 * Collection of paytable variants for all symbols.
 * Example: { "0": { default: [...], wild: [...] }, ... }
 */
export type Paytables = Record<SymbolId, PaytableVariants>;

/**
 * A special symbol declaration in the options (wild, scatter, etc.).
 */
export type SpecialSymbol = {
    /** Kind/category of special symbol (e.g., "wild", "scatter"). */
    kind: SymbolType;
    /** Symbol id that represents this special symbol on reels/screen. */
    symbol: SymbolId;
};

/**
 * Known reel set names. Backend may provide a partial subset of these.
 */
export type ReelType = "main" | "freespins" | "respin";

/**
 * A reel set for a mode: array of reels, each reel is a sequential list of symbol ids.
 * Shape: reels[reelIndex][stripIndex] -> SymbolId
 */
export type ReelSet = SymbolId[][];

/**
 * A rendered screen: 2D array of symbol ids with shape [reels][rows].
 * Each inner array represents a single reel from top to bottom (row indices).
 */
export type ScreenMap = SymbolId[][];

/**
 * Multipliers/price map for purchasable features (in subunits).
 * Example: { freespin_buy: 21600 }
 */
export type FeatureMultipliers = Record<FeatureName, Money>;

/**
 * Screen cell coordinate: [columnIndex, rowIndex].
 */
export type Cell = [number, number];

/**
 * Line coordinate definition (per reel, the row index used on that reel).
 * Example: [0, 1, 0, 1, 0]
 */
export type LineCoords = number[];

/**
 * Hit map for one special symbol: symbolId -> list of cell coordinates.
 */
export type SpecialSymbolHits = Record<SymbolId, Cell[]>;

/**
 * Special symbols that appeared on the outcome screen,
 * grouped by special type then by symbol id.
 */
export type SpecialSymbolsMap = Record<SymbolType, SpecialSymbolHits>;

/**
 * Currency metadata for formatting and conversions.
 */
export interface CurrencyMeta {
    /** ISO 4217 code (e.g., "EUR", "USD"). */
    code: "USD" | "EUR" | string;
    /** Currency symbol (e.g., "€", "$"). */
    symbol: string;
    /** Number of subunits in one major unit (e.g., 100 => 1.00). */
    subunits: number;
    /** Decimal exponent to display (e.g., 2 => show 1.00). */
    exponent: number;
}

/**
 * Slot layout: number of reels (columns) and rows (visible cells per reel).
 */
export interface Layout {
    /** Number of reels (columns). */
    reels: number;
    /** Number of rows (rows per reel). */
    rows: number;
}

/**
 * Standard feature counters exposed by the backend.
 * This object is extensible with any additional game‑specific fields
 * (e.g., sticky_wilds, expanding_symbols, etc.).
 */
export interface BaseFeatures {
    /** Total freespins issued in this bonus sequence. */
    freespins_issued?: number;
    /** Freespins remaining. */
    freespins_left?: number;
    /** Total respins issued in this bonus sequence. */
    respins_issued?: number;
    /** Respins remaining. */
    respins_left?: number;
    /** Custom, game‑specific fields. */
    [k: string]: unknown;
}

/**
 * Feature options: price list for purchasable features and a list of disabled features.
 */
export interface FeatureOptions {
    /** Map of feature name -> price in subunits. */
    feature_multipliers: FeatureMultipliers;
    /** Internally disabled features (names). */
    disabled_features: string[];
}

/**
 * Balance section of responses.
 */
export interface Balance {
    /** Accumulated win amount for the current game round (in subunits). */
    game: Money;
    /** Total wallet balance (in subunits). */
    wallet: Money;
    /** Optional free rounds balance (if used by integration). */
    free_rounds?: Money;
}

/**
 * Flow section of responses; describes current round/action context.
 */
export interface Flow {
    /** Current game round id, or null if not started. */
    round_id: null | number;
    /** Composite action id "<round>_<actionIndex>" or null. */
    last_action_id: null | string;
    /** Current game state. */
    state: FlowState;
    /** Command that produced the response. */
    command: FlowCommand;
    /** Commands that are currently allowed. */
    available_actions: FlowCommand[];
    /** Info about a purchased feature (if any). */
    purchased_feature: FlowPurchasedFeature;
}

/**
 * Purchased feature payload within the flow.
 */
export interface FlowPurchasedFeature {
    /** Name of the purchased feature (e.g., "freespin_buy"). */
    name?: FeatureName;
}

/**
 * Game configuration returned by the `init` action.
 */
export interface Options {
    /** Array of available bet values in subunits. */
    available_bets: Money[];
    /** Default bet value in subunits. */
    default_bet: Money;
    /**
     * Base bet, used to derive bet per line:
     * `bet_per_line = bet / base_bet`.
     */
    base_bet: Money;
    /** Primary paytable: symbol id -> payouts. */
    paytable: Paytable;
    /** Optional extended paytables with variants per symbol. */
    paytables?: Paytables;
    /** Declared special symbols for the game (kinds and symbol ids). */
    special_symbols: SpecialSymbol[];
    /**
     * Win lines: each line is an array of row indices,
     * its length equals the number of reels.
     */
    lines: LineCoords[];
    /**
     * Reel strips by mode (e.g., main/freespins/respin).
     * Backend may return a partial subset.
     */
    reels?: Partial<Record<ReelType, ReelSet>>;
    /** Screen layout (reels x rows). */
    layout: Layout;
    /** Currency metadata. */
    currency: CurrencyMeta;
    /** Safe screen (without wins) to display on init. */
    screen: ScreenMap;
    /** Feature multipliers and disabled features. */
    feature_options: FeatureOptions;
}

/**
 * Outcome of a single spin/freespin/respin action.
 */
export interface Outcome {
    /** Final screen after the spin (reels x rows). */
    screen: ScreenMap;
    /** Bet used for this outcome (in subunits). */
    bet: Money;
    /** Total win amount for this outcome (in subunits). */
    win: Money;
    /**
     * List of wins (lines/clusters, etc.).
     * See `LineWin` and `ClusterWin` tuple types below.
     */
    wins: Win[];
    /**
     * Special symbols detected on the final screen.
     * May be a map, an empty object, or null; omitted if absent.
     */
    special_symbols?: SpecialSymbolsMap | Record<string, never> | null;
    /**
     * Arbitrary per‑spin storage. Backend can store any data here.
     * Structure is intentionally loose and game‑specific.
     */
    storage?: Record<string, unknown>;
    /** (Sometimes present) Freespins issued counter. */
    freespins_issued?: number;
    /** (Sometimes present) Respins issued counter. */
    respins_issued?: number;
}

/**
 * Line win tuple:
 * ["line", win, lineCoords, lineId]
 * Example: ["line", 180, [0,0,0,0], 0]
 */
export type LineWin = ["line", Money, LineCoords, number];

/**
 * Cluster win tuple (two accepted forms):
 * ["cluster", win, cells, symbolId, clusterId]  or
 * ["cluster_#", win, cells, symbolId, clusterId]
 * Example: ["cluster_0", 2, [[0,0],[0,1],...], "7", 1]
 */
export type ClusterWin =
  | ["cluster", Money, Cell[], SymbolId, number]
  | [`cluster_${number}`, Money, Cell[], SymbolId, number];

/**
 * Union of all supported win tuple shapes for Outcome.wins.
 */
export type Win = LineWin | ClusterWin;

/**
 * Backend error code.
 * The union lists known codes but remains extensible.
 */
export type ErrorCode =
  | 101 | 102 | 103 | 104 | 105
  | 201 | 202 | 203 | 204 | 205
  | 206 | 301 | 302 | 303 | 401
  | 600 | 700
  | number;

/**
 * Error entry in a response.
 */
export interface ApiError {
    /** Numerical error code. */
    code: ErrorCode;
    /** Short description string (e.g., "unknown_action"). */
    desc: string;
}

/**
 * Base envelope of any API response.
 */
export interface BaseApiEnvelope {
    /** API version string (e.g., "2"). */
    api_version: ApiVer;
    /** Optional list of errors for the response. */
    errors?: ApiError[];
}


/**
 * Casino-provided free rounds information.
 */
export interface FreeRounds {
    /** Current status of the free rounds series. */
    status: "available" | "active" | "played" | string;
    /** Bet level index used for the free rounds.
     * @deprecated
     * */
    bet_level: number;
    /** Bet value for the free rounds (in subunits). */
    bet_value: number;
    /** Number of free rounds already played. */
    performed: number;
    /** Total number of free rounds granted. */
    count: number;
}
