#pragma once
#define IMGUI_DEFINE_MATH_OPERATORS
#include <core/inc.hpp>

#define M_PI   3.14159265358979323846264338327950288

auto effects::Effect::DrawSnowflake( ImDrawList* drawList, const ImVec2& center, float size, float rotation, float alpha ) -> void
{
    const int num_branches = 6;
    ImU32 color = IM_COL32( 255, 255, 255, static_cast< int >( 255 * alpha ) );

    for ( int i = 0; i < num_branches; i++ ) {
        float angle = rotation + ( i * 2 * M_PI / num_branches );


        ImVec2 tip(
            center.x + cos( angle ) * size,
            center.y + sin( angle ) * size
        );
        drawList->AddLine( center, tip, color, 2.0f );

        float branch_len = size * 0.4f;
        float side_angle1 = angle + 0.5f;
        float side_angle2 = angle - 0.5f;


        ImVec2 branch_start(
            center.x + cos( angle ) * ( size * 0.4f ),
            center.y + sin( angle ) * ( size * 0.4f )
        );


        ImVec2 side_tip1(
            branch_start.x + cos( side_angle1 ) * branch_len,
            branch_start.y + sin( side_angle1 ) * branch_len
        );
        ImVec2 side_tip2(
            branch_start.x + cos( side_angle2 ) * branch_len,
            branch_start.y + sin( side_angle2 ) * branch_len
        );

        drawList->AddLine( branch_start, side_tip1, color, 1.5f );
        drawList->AddLine( branch_start, side_tip2, color, 1.5f );


        float sec_branch_len = size * 0.2f;
        ImVec2 sec_branch_start(
            center.x + cos( angle ) * ( size * 0.7f ),
            center.y + sin( angle ) * ( size * 0.7f )
        );

        ImVec2 sec_tip1(
            sec_branch_start.x + cos( side_angle1 ) * sec_branch_len,
            sec_branch_start.y + sin( side_angle1 ) * sec_branch_len
        );
        ImVec2 sec_tip2(
            sec_branch_start.x + cos( side_angle2 ) * sec_branch_len,
            sec_branch_start.y + sin( side_angle2 ) * sec_branch_len
        );

        drawList->AddLine( sec_branch_start, sec_tip1, color, 1.0f );
        drawList->AddLine( sec_branch_start, sec_tip2, color, 1.0f );


        float inner_size = size * 0.15f;
        for ( int j = 0; j < num_branches; j++ ) {
            float inner_angle = rotation + ( j * 2 * M_PI / num_branches );
            ImVec2 inner_point(
                center.x + cos( inner_angle ) * inner_size,
                center.y + sin( inner_angle ) * inner_size
            );
            drawList->AddLine( center, inner_point, color, 1.0f );
        }
    }

    drawList->AddCircleFilled( center, size * 0.05f, color );
}

auto effects::Effect::AddSnowflake( bool randomY ) -> void
{
    ImVec2 screenSize = ImVec2( g_engine->width, g_engine->height );

    Snowflake flake;
    flake.pos.x = static_cast< float >( rand( ) ) / RAND_MAX * screenSize.x;
    flake.pos.y = randomY ? static_cast< float >( rand( ) ) / RAND_MAX * screenSize.y : -MAX_SIZE;
    flake.speed = MIN_SPEED + static_cast< float >( rand( ) ) / RAND_MAX * ( MAX_SPEED - MIN_SPEED );
    flake.size = MIN_SIZE + static_cast< float >( rand( ) ) / RAND_MAX * ( MAX_SIZE - MIN_SIZE );
    flake.alpha = 0.7f + static_cast< float >( rand( ) ) / RAND_MAX * 0.3f;
    flake.rotation = static_cast< float >( rand( ) ) / RAND_MAX * M_PI;
    flake.rotation_speed = ( static_cast< float >( rand( ) ) / RAND_MAX * 0.5f - 0.25f );

    snowflakes.push_back( flake );
}

auto effects::Effect::UpdateSnow( float deltaTime ) -> void
{
    ImVec2 screenSize = ImVec2( g_engine->width, g_engine->height );

    for ( auto& flake : snowflakes ) {
        flake.pos.y += flake.speed * deltaTime;
        flake.rotation += flake.rotation_speed * deltaTime;

        if ( flake.pos.y > screenSize.y + flake.size ) {
            flake.pos.y = -flake.size;
            flake.pos.x = static_cast< float >( rand( ) ) / RAND_MAX * screenSize.x;
        }
    }
}

auto effects::Effect::RenderSnow() -> void
{
    ImDrawList* drawList = ImGui::GetBackgroundDrawList( );

    for ( const auto& flake : snowflakes ) {
        DrawSnowflake(
            drawList,
            flake.pos,
            flake.size,
            flake.rotation,
            flake.alpha
        );
    }
}