// Copyright ExByte Studios. Item Interaction Ecosystem.

#include "ItemDeveloperModule.h"
#include "ItemEcosystemSettings.h"
#include "ItemDefinitionRow.h"
#include "Engine/DataTable.h"
#include "ToolMenus.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"

DEFINE_LOG_CATEGORY_STATIC(LogItemDeveloper, Log, All);

#define LOCTEXT_NAMESPACE "ItemDeveloper"

void FItemDeveloperModule::StartupModule()
{
	UToolMenus::RegisterStartupCallback(
		FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FItemDeveloperModule::RegisterMenus));
}

void FItemDeveloperModule::ShutdownModule()
{
	UToolMenus::UnRegisterStartupCallback(this);
	UToolMenus::UnregisterOwner(this);
}

void FItemDeveloperModule::RegisterMenus()
{
	FToolMenuOwnerScoped OwnerScoped(this);

	UToolMenu* ToolsMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Tools");
	if (!ToolsMenu)
	{
		return;
	}
	FToolMenuSection& Section = ToolsMenu->AddSection("ItemEcosystem", LOCTEXT("ItemEcosystemSection", "Item Ecosystem"));
	Section.AddMenuEntry(
		"ValidateItemData",
		LOCTEXT("ValidateItemData", "Validate Item Data"),
		LOCTEXT("ValidateItemDataTip", "Run data validation over DT_Items (section 28)."),
		FSlateIcon(),
		FUIAction(FExecuteAction::CreateStatic(&FItemDeveloperModule::ValidateAllItems)));

	Section.AddMenuEntry(
		"ExportItemsCsv",
		LOCTEXT("ExportItemsCsv", "Export DT_Items to CSV"),
		LOCTEXT("ExportItemsCsvTip", "Write DT_Items to Saved/ItemEcosystem/DT_Items.csv (section 27)."),
		FSlateIcon(),
		FUIAction(FExecuteAction::CreateStatic(&FItemDeveloperModule::ExportItemsToCsv)));

	Section.AddMenuEntry(
		"ReportMissingAssets",
		LOCTEXT("ReportMissingAssets", "Report: Items Missing Icon/Mesh"),
		LOCTEXT("ReportMissingAssetsTip", "List items with no Icon or WorldMesh (section 27)."),
		FSlateIcon(),
		FUIAction(FExecuteAction::CreateStatic(&FItemDeveloperModule::ReportMissingAssets)));
}

void FItemDeveloperModule::ExportItemsToCsv()
{
	const UItemEcosystemSettings* Settings = UItemEcosystemSettings::Get();
	UDataTable* ItemsTable = Settings ? Settings->ItemsTable.LoadSynchronous() : nullptr;
	if (!ItemsTable)
	{
		FNotificationInfo Info(LOCTEXT("NoItemsTable", "DT_Items is not assigned."));
		Info.ExpireDuration = 5.f;
		FSlateNotificationManager::Get().AddNotification(Info);
		return;
	}

	const FString Csv = ItemsTable->GetTableAsCSV();
	const FString Path = FPaths::ProjectSavedDir() / TEXT("ItemEcosystem") / TEXT("DT_Items.csv");
	const bool bOk = FFileHelper::SaveStringToFile(Csv, *Path);

	const FText Msg = bOk
		? FText::Format(LOCTEXT("ExportOk", "Exported DT_Items to {0}"), FText::FromString(Path))
		: LOCTEXT("ExportFail", "Failed to write CSV.");
	FNotificationInfo Info(Msg);
	Info.ExpireDuration = 6.f;
	FSlateNotificationManager::Get().AddNotification(Info);
	UE_LOG(LogItemDeveloper, Log, TEXT("CSV export: %s -> %s"), bOk ? TEXT("OK") : TEXT("FAIL"), *Path);
}

void FItemDeveloperModule::ReportMissingAssets()
{
	const UItemEcosystemSettings* Settings = UItemEcosystemSettings::Get();
	UDataTable* ItemsTable = Settings ? Settings->ItemsTable.LoadSynchronous() : nullptr;
	if (!ItemsTable)
	{
		return;
	}

	int32 Missing = 0;
	TArray<FItemDefinitionRow*> Rows;
	ItemsTable->GetAllRows<FItemDefinitionRow>(TEXT("ItemDeveloper.ReportMissing"), Rows);
	for (const FItemDefinitionRow* Row : Rows)
	{
		if (!Row) { continue; }
		if (Row->Icon.IsNull()) { ++Missing; UE_LOG(LogItemDeveloper, Warning, TEXT("%s: no Icon"), *Row->ItemId.ToString()); }
		if (Row->WorldMesh.IsNull()) { ++Missing; UE_LOG(LogItemDeveloper, Warning, TEXT("%s: no WorldMesh"), *Row->ItemId.ToString()); }
	}

	FNotificationInfo Info(FText::Format(LOCTEXT("MissingResult", "Asset report: {0} missing reference(s). See Output Log."), FText::AsNumber(Missing)));
	Info.ExpireDuration = 6.f;
	FSlateNotificationManager::Get().AddNotification(Info);
}

void FItemDeveloperModule::ValidateAllItems()
{
	const UItemEcosystemSettings* Settings = UItemEcosystemSettings::Get();
	UDataTable* ItemsTable = Settings ? Settings->ItemsTable.LoadSynchronous() : nullptr;

	int32 Errors = 0;
	int32 Warnings = 0;

	auto Report = [&](const FName& Id, const FString& Msg, bool bError)
	{
		bError ? ++Errors : ++Warnings;
		UE_LOG(LogItemDeveloper, Warning, TEXT("[%s] %s: %s"), bError ? TEXT("ERROR") : TEXT("WARN"), *Id.ToString(), *Msg);
	};

	if (!ItemsTable)
	{
		UE_LOG(LogItemDeveloper, Error, TEXT("DT_Items is not assigned in Project Settings -> Item Ecosystem."));
	}
	else
	{
		TArray<FItemDefinitionRow*> Rows;
		ItemsTable->GetAllRows<FItemDefinitionRow>(TEXT("ItemDeveloper.Validate"), Rows);
		for (const FItemDefinitionRow* Row : Rows)
		{
			if (!Row) { continue; }
			const FName Id = Row->ItemId;
			if (Id.IsNone()) { Report(Id, TEXT("ItemId is empty."), true); }
			if (Row->MaxStack <= 0) { Report(Id, TEXT("MaxStack <= 0."), true); }
			if (Row->GridSize.X <= 0 || Row->GridSize.Y <= 0) { Report(Id, TEXT("GridSize must be >= 1."), true); }
			if (Row->bCanInstantPickup && !Row->bCanStoreInInventory) { Report(Id, TEXT("InstantPickup but not storable."), true); }
			if (Row->bCanEquip && Row->EquippedActorClass.IsNull()) { Report(Id, TEXT("CanEquip but no EquippedActorClass."), true); }
			if (Row->bCanWorldCarry && Row->WorldMesh.IsNull()) { Report(Id, TEXT("CanWorldCarry but no WorldMesh."), true); }
			if (Row->bCanInstallIntoWorldSlot && Row->CompatibleWorldSlots.IsEmpty()) { Report(Id, TEXT("CanInstall but no CompatibleWorldSlots."), true); }
			if (Row->bIsQuestCritical && Row->bCanDrop) { Report(Id, TEXT("QuestCritical item is droppable."), false); }
		}
		UE_LOG(LogItemDeveloper, Log, TEXT("Validated %d item rows."), Rows.Num());
	}

	const FText Summary = FText::Format(
		LOCTEXT("ValidateResult", "Item validation: {0} error(s), {1} warning(s). See Output Log."),
		FText::AsNumber(Errors), FText::AsNumber(Warnings));
	FNotificationInfo Info(Summary);
	Info.ExpireDuration = 6.f;
	FSlateNotificationManager::Get().AddNotification(Info);
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FItemDeveloperModule, ItemDeveloper)
