// State.h - base class and shared context for app states
#pragma once
#include <SDL3/SDL.h>
#include <memory>
#include <vector>
#include <functional>
#include <string>
#include <array>
#include <cstdint>

#include "../network/NetSession.h"

// Forward declarations for frequently used types
class Game;
class CoopGame;
class ScoreManager;
class Starfield;
class Starfield3D;
class FontAtlas;
class LineEffect;
enum class AppState;

// Forward declare StateManager so StateContext can hold a pointer without
// including the StateManager header here.
class StateManager;

// Shared context passed to states so they can access common resources
struct StateContext {
    // Core subsystems (may be null if not available)
    Game* game = nullptr;
    CoopGame* coopGame = nullptr;
    ScoreManager* scores = nullptr;
    Starfield* starfield = nullptr;
    Starfield3D* starfield3D = nullptr;
    FontAtlas* font = nullptr;
    FontAtlas* pixelFont = nullptr;
    LineEffect* lineEffect = nullptr;

    // Textures
    SDL_Texture* logoTex = nullptr;
    SDL_Texture* logoSmallTex = nullptr;
    int logoSmallW = 0;
    int logoSmallH = 0;
    SDL_Texture* backgroundTex = nullptr;
    // backgroundTex is set once in `main.cpp` and passed to states via this context.
    // Prefer reading this field instead of relying on any `extern SDL_Texture*` globals.
    SDL_Texture* blocksTex = nullptr;
    SDL_Texture* asteroidsTex = nullptr;
    SDL_Texture* scorePanelTex = nullptr;
    SDL_Texture* statisticsPanelTex = nullptr;
    SDL_Texture* nextPanelTex = nullptr;
    SDL_Texture* holdPanelTex = nullptr; // Background for the HOLD preview
    SDL_Texture* mainScreenTex = nullptr;
    int mainScreenW = 0;
    int mainScreenH = 0;
    // Captured full-scene texture (used by menu for backdrop blur effects)
    SDL_Texture* sceneTex = nullptr;
    int sceneW = 0;
    int sceneH = 0;

    // Audio / SFX - forward declared types in main
    // Pointers to booleans/flags used by multiple states
    bool* musicEnabled = nullptr;
    bool* musicStarted = nullptr;
    bool* musicLoaded = nullptr;
    int* startLevelSelection = nullptr;
    int* hoveredButton = nullptr;
    // Menu popups (exposed from main)
    bool* showSettingsPopup = nullptr;
    bool* showHelpOverlay = nullptr;
    bool* showExitConfirmPopup = nullptr; // If true, show "Exit game?" confirmation while playing
    int* exitPopupSelectedButton = nullptr; // 0 = YES, 1 = NO (default)
    bool* gameplayCountdownActive = nullptr; // True if start-of-game countdown is running
    bool* menuPlayCountdownArmed = nullptr; // True if we are transitioning to play and countdown is pending
    bool* skipNextLevelUpJingle = nullptr; // Allows states to silence initial level-up SFX
    // Challenge clear FX (slow block-by-block explosion before next level)
    bool* challengeClearFxActive = nullptr;
    double* challengeClearFxElapsedMs = nullptr;
    double* challengeClearFxDurationMs = nullptr;
    std::vector<int>* challengeClearFxOrder = nullptr;
    std::string* challengeStoryText = nullptr; // Per-level briefing string for Challenge mode
    int* challengeStoryLevel = nullptr; // Cached level for the current story line
    float* challengeStoryAlpha = nullptr; // Current render alpha for story text fade
    std::string* playerName = nullptr; // Shared player name buffer for highscores/options
    // Coop setting: when true, COOPERATE runs with a computer-controlled right player.
    bool* coopVsAI = nullptr;

    // COOPERATE (network) --------------------------------------------------
    // These fields are only meaningful when `coopNetEnabled` is true.
    bool coopNetEnabled = false;
    bool coopNetIsHost = false;
    bool coopNetLocalIsLeft = true; // host = left (WASD), client = right (arrows)
    uint32_t coopNetRngSeed = 0;
    uint32_t coopNetTick = 0;
    uint8_t coopNetPendingButtons = 0; // one-shot actions captured from keydown (rotate/hold/harddrop)
    bool coopNetStalled = false; // true when waiting for remote input for current tick
    bool coopNetDesyncDetected = false;
    std::string coopNetUiStatusText; // transient status shown in menu after net abort
    double coopNetUiStatusRemainingMs = 0.0;
    std::unique_ptr<NetSession> coopNetSession;
    bool* fullscreenFlag = nullptr; // Tracks current fullscreen state when available
    std::function<void(bool)> applyFullscreen; // Allows states to request fullscreen changes
    std::function<bool()> queryFullscreen; // Optional callback if fullscreenFlag is not reliable
    std::function<void()> requestQuit; // Allows menu/option states to close the app gracefully
    std::function<void()> startPlayTransition; // Optional fade hook when transitioning from menu to gameplay
    std::function<void(AppState)> requestFadeTransition; // Generic state fade requests (menu/options/level)

    // Startup transition fade (used for intro video -> main).
    // When active, the app should render a black overlay with alpha = startupFadeAlpha*255.
    bool* startupFadeActive = nullptr;
    float* startupFadeAlpha = nullptr;
    // Pointer to the application's StateManager so states can request transitions
    StateManager* stateManager = nullptr;
    // Optional explicit per-button coordinates (logical coordinates). When
    // `menuButtonsExplicit` is true, MenuState will use these centers for
    // rendering and hit tests. Values are in logical units (LOGICAL_W/H).
    std::array<float, 4> menuButtonCX{};
    std::array<float, 4> menuButtonCY{};
    bool menuButtonsExplicit = false;
};

class State {
public:
    explicit State(StateContext& ctx) : ctx(ctx) {}
    virtual ~State() = default;

    virtual void onEnter() {}
    virtual void onExit() {}
    virtual void handleEvent(const SDL_Event& e) {}
    virtual void update(double frameMs) {}
    virtual void render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logicalVP) {}

protected:
    StateContext& ctx;
};
