#include "crDevApp.h"

#include <SDL3/SDL_log.h>
#include <imgui.h>

#include "crApp.h"
#include "crBuildInfo.h"
#include "crDevAudio.h"
#include "crDevCamera.h"
#include "crDevConsole.h"
#include "crDevGizmos.h"
#include "crDevGraphics.h"
#include "crDevPostProcess.h"
#include "crDevProfiler.h"
#include "crDevUtils.h"
#include "crEcs.h"

void crDevApp::Init()
{

}
void crDevApp::Cleanup()
{

}

/*static*/ void crDevApp::ScaleUi( float scale )
{
    static const ImGuiStyle BASE = ImGui::GetStyle();   // ScaleAllSizes compounds, so restart from it

    ImGuiStyle& style = ImGui::GetStyle();
    style = BASE;
    style.ScaleAllSizes( scale );
    style.FontScaleMain = scale;
}

void crDevApp::TryRenderPanel( crApp* app )
{
    if( enabled == false )
        return;

    const uint32_t flags = app->AppStateRaw();

    const ImGuiViewport* viewport = ImGui::GetMainViewport();
    const float          pad      = 10.0f;

    ImVec2 pos;
    pos.x = viewport->WorkPos.x + viewport->WorkSize.x - pad;
    pos.y = viewport->WorkPos.y + viewport->WorkSize.y - pad;
    // the toggle at the bottom writes `folded` mid-frame; every push below has to be popped against the value it was pushed with
    const bool wasFolded = folded;

    ImGui::SetNextWindowPos( pos, ImGuiCond_Always, ImVec2( 1.0f, 1.0f ) );   // pivot bottom-right
    if( wasFolded == false )
        ImGui::SetNextWindowSizeConstraints( ImVec2( 400.0f, 0.0f ), ImVec2( 4096.0f, 4096.0f ) );

    ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoTitleBar
                                 | ImGuiWindowFlags_NoMove
                                 | ImGuiWindowFlags_NoResize
                                 | ImGuiWindowFlags_AlwaysAutoResize
                                 | ImGuiWindowFlags_NoSavedSettings;

    ImGui::PushStyleVar( ImGuiStyleVar_WindowBorderSize, 0.0f );
    ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 8.0f, -1.0f ) );
    if( wasFolded )
        ImGui::PushStyleColor( ImGuiCol_WindowBg, ImVec4( 0.0f, 0.0f, 0.0f, 0.0f ) );

    ImGui::Begin( "Dev App", nullptr, windowFlags );

    if( wasFolded == false )
    {
        struct FlagLabel
        {
            crApp::EAppStateFlags flag;
            const char*           label;
            bool                  newRow;
        };
        static const FlagLabel TABLE[] =
        {
            { crApp::EAppStateFlags::INITTED,           "INITTED     ",        true  },
            { crApp::EAppStateFlags::FILE_IO_PENDING,   "FILE_IO_PENDING    ", false },
            { crApp::EAppStateFlags::BACKGROUNDED,      "BACKGROUNDED",        false },
            { crApp::EAppStateFlags::SIM_PAUSED,        "SIM_PAUSED  ",        true  },
            { crApp::EAppStateFlags::RUN_IN_BACKGROUND, "RUN_IN_BACKGROUND",   false },
        };
        const ImVec4 LIT   = ImVec4( 0.45f, 0.95f, 0.60f, 1.0f );
        const ImVec4 UNLIT = ImVec4( 0.34f, 0.35f, 0.42f, 1.0f );

        char text[ 96 ];
        SDL_snprintf( text, sizeof( text ), "buildstamp %s", crBuildInfo::STAMP );
        crDevUtils::TextRight( text );

        for( size_t i = 0; i < SDL_arraysize( TABLE ); ++i )
        {
            if( TABLE[ i ].newRow == false )
                ImGui::SameLine( 0.0f, 0.0f );   // zero spacing: the label's own padding is the gap

            const bool on = ( ( flags & ( uint32_t )TABLE[ i ].flag ) != 0 );
            ImGui::TextColored( on ? LIT : UNLIT, "%s", TABLE[ i ].label );
        }

        SDL_snprintf( text, sizeof( text ), "uptime %" SDL_PRIu64 " ms", SDL_GetTicks() );
        crDevUtils::TextRight( text );

        {// the -1 spacing above is for the text rows; widgets need a real one
            ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 8.0f, 2.0f ) );

            ImGui::Separator();
            ImGui::BeginDisabled( app->targetFps <= 0.0f );
            ImGui::SetNextItemWidth( 110.0f );
            ImGui::SliderFloat( "target fps", &app->targetFps, 30.0f, 120.0f, "%.0f" );
            ImGui::EndDisabled();

            ImGui::SameLine();
            if( ImGui::RadioButton( "off", app->targetFps <= 0.0f ) )
                app->targetFps = 0.0f;
            ImGui::SameLine();
            if( ImGui::RadioButton( "30", app->targetFps == 30.0f ) )
                app->targetFps = 30.0f;
            ImGui::SameLine();
            if( ImGui::RadioButton( "60", app->targetFps == 60.0f ) )
                app->targetFps = 60.0f;
            ImGui::SameLine();
            if( ImGui::RadioButton( "120", app->targetFps == 120.0f ) )
                app->targetFps = 120.0f;

            bool fullscreen = app->IsFullscreen();
            if( ImGui::Checkbox( "fullscreen", &fullscreen ) )
                app->SetFullscreen( fullscreen );

            ImGui::SameLine();
            bool runBg = app->IsRunInBackground();   // off = the sim halts once backgrounded
            if( ImGui::Checkbox( "runbg", &runBg ) )
                app->SetRunInBackground( runBg );

            ImGui::Separator();

            // both write the same single truth the game writes — whoever writes last wins
            bool simActive = app->IsSimulationActive();
            if( ImGui::Checkbox( "sim active", &simActive ) )
                app->SetSimulationActive( simActive );

            ImGui::SameLine();
            float simSpeed = app->SimulationSpeed();
            ImGui::SetNextItemWidth( 110.0f );
            if( ImGui::SliderFloat( "sim speed", &simSpeed, 0.1f, 10.0f, "%.2f" ) )
                app->SetSimulationSpeed( simSpeed );

            ImGui::SameLine();
            SDL_snprintf( text, sizeof( text ), "step %" SDL_PRIu64, app->SimulationStepIndex() );
            crDevUtils::TextRight( text );

            ImGui::Separator();

            ImGui::Checkbox( "console", &app->devConsole->enabled );

            ImGui::Separator();
            if( ImGui::CollapsingHeader( "Dev Panels" ) )
            {
                if( crDevUtils::ButtonRight( "Hide All Panels" ) )
                {
                    app->devAudio->enabled       = false;
                    app->devCamera->enabled      = false;
                    app->devGizmos->enabled      = false;
                    app->devGraphics->enabled    = false;
                    app->devPostProcess->enabled = false;
                    app->devProfiler->enabled    = false;
                }

                // explicit outer width: stretch columns in an AlwaysAutoResize window would otherwise
                // size themselves from a width that is itself being sized from them
                const ImGuiTableFlags tableFlags = ( ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchSame );

                if( ImGui::BeginTable( "devpanels", 2, tableFlags, ImVec2( ImGui::GetContentRegionAvail().x, 0.0f ) ) )
                {
                    ImGui::TableNextColumn();  ImGui::Checkbox( "Audio",       &app->devAudio->enabled );
                    ImGui::TableNextColumn();  ImGui::Checkbox( "Camera",      &app->devCamera->enabled );

                    ImGui::TableNextColumn();  ImGui::Checkbox( "Gizmos",      &app->devGizmos->enabled );
                    ImGui::TableNextColumn();  ImGui::Checkbox( "Graphics",    &app->devGraphics->enabled );

                    ImGui::TableNextColumn();  ImGui::Checkbox( "PostProcess", &app->devPostProcess->enabled );
                    ImGui::TableNextColumn();  ImGui::Checkbox( "Profiler",    &app->devProfiler->enabled );

                    ImGui::EndTable();
                }
            }

            ImGui::PopStyleVar();
        }
    }

    {// last and right-aligned, so the window's bottom-right pivot parks it in the screen corner and
        // folding collapses the panel onto it rather than moving it
        ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 8.0f, 2.0f ) );

        const float width = ( ImGui::GetFrameHeight() + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::CalcTextSize( "crDev" ).x );
        const float avail = ImGui::GetContentRegionAvail().x;
        if( avail > width )
            ImGui::SetCursorPosX( ImGui::GetCursorPosX() + ( avail - width ) );

        bool open = ( folded == false );
        if( ImGui::Checkbox( "crDev", &open ) )
            folded = ( open == false );

        ImGui::PopStyleVar();
    }

    ImGui::End();

    if( wasFolded )
        ImGui::PopStyleColor();
    ImGui::PopStyleVar( 2 );
}
