#include "VentuzEditorPluginModule.h"

#include "DetailCustomizations.h"
#include "Engine.h"
#include "LevelEditor.h"
#include "AssetRegistryModule.h"
#include "Kismet2/StructureEditorUtils.h"
#include "EdGraphSchema_K2.h"
#include "VentuzBPEvent.h"
#include "VentuzPluginModule.h"
#include "UserDefinedStructure/UserDefinedStructEditorData.h"
#include "UnrealEd/Public/FileHelpers.h"
#include "UObject/UObjectGlobals.h"
#include "ObjectTools.h"

DEFINE_LOG_CATEGORY( VentuzEditorPluginLog )

Ventuz::UE4::FieldDescriptor ToVentuzFieldDescriptor( const FVentuzNodeField& field )
{
    Ventuz::UE4::FieldDescriptor result;

    result.fieldName = std::string( TCHAR_TO_UTF8( *field.fieldName ) );
    result.fromVentuz = field.direction == VentuzCommunicationDirection::FromVentuz;
    result.type = ( Ventuz::E2EFieldType )field.fieldType;

    return result;
}

std::vector<Ventuz::UE4::FieldDescriptor> GatherFieldsToSend( const std::string& nodeName )
{
    FString nodeNameFstr( UTF8_TO_TCHAR( nodeName.c_str() ) );

    //TArray<FVentuzNodeField> fieldsToSend;
    std::vector<Ventuz::UE4::FieldDescriptor> fieldsToSend;

    for ( TObjectIterator<UVentuzE2ESyncNodeBase> it; it; ++it )
    {
        if ( it->nodeInVentuzToSyncFrom == nodeNameFstr )
        {
            UVentuzE2ESyncNodeBase* base = *it;

            if ( base->IsA<UVentuzE2EGetData>() )
            {
                auto getDataNode = Cast<UVentuzE2EGetData>( base );

                for ( auto& field : getDataNode->fromVentuzFields )
                {
                    bool found = false;
                    for ( auto& otherField : fieldsToSend )
                    {
                        if ( otherField.fromVentuz == ( field.direction == VentuzCommunicationDirection::FromVentuz ) && otherField.fieldName == std::string( TCHAR_TO_UTF8( *field.fieldName ) ) )
                        {
                            found = true;
                        }
                    }

                    if ( !found )
                        fieldsToSend.emplace_back( ToVentuzFieldDescriptor( field ) );
                }
            }

            if ( base->IsA<UVentuzE2ESendData>() )
            {
                auto sendDataNode = Cast<UVentuzE2ESendData>( base );

                for ( auto& field : sendDataNode->toVentuzFields )
                {
                    bool found = false;
                    for ( auto& otherField : fieldsToSend )
                    {
                        if ( otherField.fromVentuz == ( field.direction == VentuzCommunicationDirection::FromVentuz ) && otherField.fieldName == std::string( TCHAR_TO_UTF8( *field.fieldName ) ) )
                        {
                            found = true;
                        }
                    }

                    if ( !found )
                        fieldsToSend.emplace_back( ToVentuzFieldDescriptor( field ) );
                }
            }
        }
    }

    return fieldsToSend;
}

FVentuzEditorPlugin::FVentuzEditorPlugin()
{
}

void FVentuzEditorPlugin::RegisterCustomClassLayout( FName ClassName, FOnGetDetailCustomizationInstance DetailLayoutDelegate )
{
    check( ClassName != NAME_None );

    RegisteredClassNames.Add( ClassName );

    static FName PropertyEditor( "PropertyEditor" );
    FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>( PropertyEditor );
    PropertyModule.RegisterCustomClassLayout( ClassName, DetailLayoutDelegate );
}

void FVentuzEditorPlugin::StartupModule()
{
    FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>( "PropertyEditor" );

    RegisterCustomClassLayout( "VentuzE2ESyncNodeBase", FOnGetDetailCustomizationInstance::CreateStatic( &FVentuzE2ESyncNodeDetails::MakeInstance ) );

    PropertyModule.NotifyCustomizationModuleChanged();
}

void FVentuzEditorPlugin::ShutdownModule()
{
    if ( FModuleManager::Get().IsModuleLoaded( "PropertyEditor" ) )
    {
        FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>( "PropertyEditor" );

        // Unregister all classes customized by name
        for ( auto It = RegisteredClassNames.CreateConstIterator(); It; ++It )
        {
            if ( It->IsValid() )
            {
                PropertyModule.UnregisterCustomClassLayout( *It );
            }
        }
        PropertyModule.NotifyCustomizationModuleChanged();
    }
}

void FVentuzEditorPlugin::Tick( float deltaTime )
{
    if ( !IVentuzPlugin::IsAvailable() )
        return;
    auto* plugin = &FModuleManager::LoadModuleChecked<FVentuzPlugin>( "VentuzPlugin" );

    if ( !plugin )
        return;

    auto requestList = plugin->GetFieldListRequests();

    for ( auto& request : requestList )
    {
        auto fieldsToSend = GatherFieldsToSend( request.second );
        plugin->SendFieldList( request.first, fieldsToSend );
    }

}

bool FVentuzEditorPlugin::IsTickableWhenPaused() const
{
    return true;
}

bool FVentuzEditorPlugin::IsTickableInEditor() const
{
    return true;
}

TStatId FVentuzEditorPlugin::GetStatId() const
{
    RETURN_QUICK_DECLARE_CYCLE_STAT( FVentuzEditorPlugin, STATGROUP_Tickables );
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE( FVentuzEditorPlugin, VentuzEditorPlugin )