// Copyright (c) 2023 Codemongous LLC. All Rights Reserved.

#include "SourcifySettings.h"
#include "ISourcifyCoreSettings.h"
#include "SourcifyCoreUEWrapperModule.h"
#include <string>
#include <vector>

using std::vector;
using std::wstring;

USourcifySettings::USourcifySettings()
{
	AssetPrefixesToIgnore =
	{
		TEXT("ABP_"),
		TEXT("B_"),
		TEXT("BP_"),
		TEXT("BPI_"),
		TEXT("E_"),
		TEXT("S_"),
		TEXT("UDE_"),
		TEXT("UDS_"),
		TEXT("W_"),
		TEXT("WB_"),
		TEXT("WBP_")
	};

	// Initialize PreviousSourcifyMetaTags with the legacy value for backward compatibility
	PreviousSourcifyMetaTags.Add(TEXT("SOURCIFIED"));

	// Initialize default struct types that should always be included
	DefaultStructTypesToInitialize =
	{
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Vector"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Vector2D"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Vector4"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Rotator"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Quat"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Transform"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Color"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.LinearColor"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.DateTime"))),
		TSoftObjectPtr<UScriptStruct>(FSoftObjectPath(TEXT("/Script/CoreUObject.Timespan")))
	};
}

FText USourcifySettings::GetSectionText() const
{
	return FText::FromString(TEXT("Sourcify"));
}

FText USourcifySettings::GetSectionDescription() const
{
	return FText::FromString(TEXT("Configure the Sourcify plugin"));
}

void USourcifySettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	if (GET_MEMBER_NAME_CHECKED(USourcifySettings, DefaultCodeExportPath) == PropertyChangedEvent.GetMemberPropertyName())
	{
		FPaths::NormalizeDirectoryName(DefaultCodeExportPath.Path);
		if (DefaultCodeExportPath.Path.StartsWith(TEXT("../")))
		{
			FString TempPath = FPaths::ConvertRelativePathToFull(DefaultCodeExportPath.Path);
			FPaths::MakePathRelativeTo(TempPath, *FPaths::ProjectDir());
			DefaultCodeExportPath.Path = TempPath;
		}
	}
}

void USourcifySettings::ToSourcifyCore(struct Sourcify::ISourcifyCoreSettings* CoreSettings) const
{
	CoreSettings->SetDeclareDelegatesInsideClass(DeclareDelegatesInsideClass);
	CoreSettings->SetIndentType(static_cast<Sourcify::SourcifyCoreSettingsEmittedCodeIndentType>(IndentType));
	CoreSettings->SetNumIndentSpaces(NumIndentSpaces);
	CoreSettings->SetNumLinesBetweenTypeDeclarations(NumLinesBetweenTypeDeclarations);
	CoreSettings->SetNumLinesBetweenFunctionAndPropertyDeclarationBlocks(NumLinesBetweenFunctionAndPropertyDeclarationBlocks);
	CoreSettings->SetNumLinesBetweenPropertyDeclarations(NumLinesBetweenPropertyDeclarations);
	CoreSettings->SetNumLinesBetweenFunctionDeclarations(NumLinesBetweenFunctionDeclarations);
	CoreSettings->SetNumLinesBetweenClassAccessBlocks(NumLinesBetweenClassAccessBlocks);
	CoreSettings->SetNumSpacesAroundEqualSignInMetaTags(NumSpacesAroundEqualSignInMetaTags);
	vector<wstring> WStringAssetPrefixesToIgnore;
	for (const FString& Prefix : AssetPrefixesToIgnore)
	{
		WStringAssetPrefixesToIgnore.push_back(wstring(*Prefix));
	}
	CoreSettings->SetAssetPrefixesToIgnore(WStringAssetPrefixesToIgnore);

	// Transfer default struct types to initialize
	vector<shared_ptr<Sourcify::ISCW_UScriptStruct>> DefaultStructsToInclude;
	for (const TSoftObjectPtr<UScriptStruct>& StructPtr : DefaultStructTypesToInitialize)
	{
		if (!StructPtr.IsNull())
		{
			UScriptStruct* LoadedStruct = StructPtr.LoadSynchronous();
			if (LoadedStruct)
			{
				DefaultStructsToInclude.push_back(Sourcify::FSourcifyCoreUEWrapper::Get().Wrap(*LoadedStruct));
			}
		}
	}
	CoreSettings->SetDefaultStructTypesToInitialize(DefaultStructsToInclude);

	// Transfer user-defined struct types to initialize
	vector<shared_ptr<Sourcify::ISCW_UScriptStruct>> UserStructsToInclude;
	for (const TSoftObjectPtr<UScriptStruct>& StructPtr : UserStructTypesToInitialize)
	{
		if (!StructPtr.IsNull())
		{
			UScriptStruct* LoadedStruct = StructPtr.LoadSynchronous();
			if (LoadedStruct)
			{
				UserStructsToInclude.push_back(Sourcify::FSourcifyCoreUEWrapper::Get().Wrap(*LoadedStruct));
			}
		}
	}
	CoreSettings->SetUserStructTypesToInitialize(UserStructsToInclude);

	CoreSettings->SetEnsurePropertiesHaveDefaultValues(EnsurePropertiesHaveDefaultValues);
	CoreSettings->SetToolTipCommentStyle(static_cast<Sourcify::SourcifyCoreSettingsToolTipCommentStyle>(ToolTipCommentStyle));
	CoreSettings->SetCurrentSourcifyMetaTag(wstring(*CurrentSourcifyMetaTag));
	vector<wstring> WStringPreviousSourcifyMetaTags;
	for (const FString& MetaTag : PreviousSourcifyMetaTags)
	{
		WStringPreviousSourcifyMetaTags.push_back(wstring(*MetaTag));
	}
	CoreSettings->SetPreviousSourcifyMetaTags(WStringPreviousSourcifyMetaTags);
	CoreSettings->SetDefaultCodeExportPath(wstring(*DefaultCodeExportPath.Path));
	CoreSettings->SetGenerateProjectFiles(GenerateProjectFiles);
}
