#include <Urho3D/Core/Context.h>
#include <Urho3D/Scene/Node.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Graphics/Material.h>
#include <Urho3D/Graphics/Model.h>
#include <Urho3D/Graphics/StaticModel.h>
#include <Urho3D/Scene/ValueAnimation.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Physics/CollisionShape.h>
#include <Urho3D/Physics/RigidBody.h>

#include "Common.h"
#include "Remover.h"
#include "Splitter.h"

namespace {
    constexpr auto E_SPLIT = "split";
}

Splitter::Splitter(Context* context) :
    LogicComponent(context)
{
}

void Splitter::RegisterObject(Context* context)
{
    context->RegisterFactory<Splitter>();
}


void Splitter::Split() {
    ValueAnimation* anim{ new ValueAnimation{ context_ } };
    auto node = GetNode();
    auto scale = node->GetScale();
    anim->SetKeyFrame(0.0f, scale);
    anim->SetKeyFrame(0.1f, Vector3::ZERO);
    anim->SetEventFrame(0.1f, E_SPLIT);
    node->SetAttributeAnimation("Scale", anim, WM_ONCE);
    node->GetComponent<RigidBody>()->Remove();
    SubscribeToEvent(node, E_SPLIT, URHO3D_HANDLER(Splitter, HandleSplitEnd));
}

void Splitter::HandleSplitEnd(StringHash eventType, VariantMap&) {
    auto node = GetNode();
    auto scene = node->GetScene();

    ResourceCache* cache = GetSubsystem<ResourceCache>();

    for (auto i = 0; i < 16; i++) {
        constexpr auto DIVISOR = 4;

        Node* boxNode = scene->CreateChild("SmallerTofu");
        boxNode->SetPosition(
                node->GetPosition() +
                Vector3(
                    Random(-0.5f, 0.5f) / DIVISOR,
                    Random(-0.5f, 0.5f) / DIVISOR,
                    Random(-0.5f, 0.5f) / DIVISOR
                    )
                );
        boxNode->SetScale(BULLET_SCALE / DIVISOR);
        auto boxObject = boxNode->CreateComponent<StaticModel>();
        boxObject->SetModel(cache->GetResource<Model>("fds/Tofu.mdl"));
        boxObject->SetMaterial(cache->GetResource<Material>("fds/TofuMaterial.xml"));
        boxObject->SetCastShadows(true);
        boxNode->CreateComponent<Remover>();

        // Create physics components, use a smaller mass also
        RigidBody* body = boxNode->CreateComponent<RigidBody>();
        body->SetMass(0.1f / DIVISOR);
        body->SetFriction(0.75f);
        body->SetLinearVelocity(
                Vector3(
                    Random(-2.0f, 2.0f),
                    Random(-2.0f, 5.0f),
                    Random(-2.0f, 2.0f)
                    )
                );
        CollisionShape* shape = boxNode->CreateComponent<CollisionShape>();
        shape->SetBox(Vector3::ONE * 2);
    }
    node->Remove();
}
