//======================================================================================================
// Company Name:       MotionTechnologies.inc
// Copyright Year:     2025
// File:               MoALiveLinkSettings.cpp
//======================================================================================================

#include "MoALiveLinkSettings.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/Paths.h"
#include "HAL/PlatformFileManager.h"
#include "Misc/FileHelper.h"

static const TCHAR* MoAConfigSection = TEXT("/Script/MoALiveLink.MoALiveLinkSettings");

UMoALiveLinkSettings::UMoALiveLinkSettings()
{
	// No default connections - only add via source creation
}

UMoALiveLinkSettings* UMoALiveLinkSettings::Get()
{
	return GetMutableDefault<UMoALiveLinkSettings>();
}

void UMoALiveLinkSettings::SaveConnectionsToConfig()
{
	// Convert to absolute path - critical for UE 5.5+
	FString ConfigDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir() / TEXT("Config"));
	FString ConfigFilename = ConfigDir / TEXT("MoALiveLink.ini");
	
	// Ensure directory exists
	IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
	if (!PlatformFile.DirectoryExists(*ConfigDir))
	{
		PlatformFile.CreateDirectoryTree(*ConfigDir);
		UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Created config directory: %s"), *ConfigDir);
	}
	
	UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Saving to: %s"), *ConfigFilename);
	
	// Build INI content directly
	FString IniContent;
	IniContent += TEXT("[") + FString(MoAConfigSection) + TEXT("]\n");
	IniContent += FString::Printf(TEXT("bAutoConnectOnStartup=%s\n"), bAutoConnectOnStartup ? TEXT("True") : TEXT("False"));
	IniContent += FString::Printf(TEXT("bRememberLastConnection=%s\n"), bRememberLastConnection ? TEXT("True") : TEXT("False"));
	
	for (const FMoALiveLinkConnectionInfo& Conn : SavedConnections)
	{
		IniContent += FString::Printf(TEXT("+SavedConnections=(IPAddress=\"%s\",Port=%d,bEnabled=%s)\n"), 
			*Conn.IPAddress, Conn.Port, Conn.bEnabled ? TEXT("True") : TEXT("False"));
	}
	
	// Write directly to file
	if (FFileHelper::SaveStringToFile(IniContent, *ConfigFilename))
	{
		UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Saved %d connections to %s"), SavedConnections.Num(), *ConfigFilename);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("[MoA LiveLink] Failed to save config file: %s"), *ConfigFilename);
	}
}

void UMoALiveLinkSettings::LoadConnectionsFromConfig()
{
	// Convert to absolute path
	FString ConfigFilename = FPaths::ConvertRelativePathToFull(FPaths::ProjectSavedDir() / TEXT("Config") / TEXT("MoALiveLink.ini"));
	
	UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Loading from: %s"), *ConfigFilename);
	
	// Check if file exists
	if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*ConfigFilename))
	{
		UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Config file not found, using defaults"));
		return;
	}
	
	// Read file content
	FString FileContent;
	if (!FFileHelper::LoadFileToString(FileContent, *ConfigFilename))
	{
		UE_LOG(LogTemp, Warning, TEXT("[MoA LiveLink] Failed to read config file"));
		return;
	}
	
	SavedConnections.Empty();
	
	// Parse line by line
	TArray<FString> Lines;
	FileContent.ParseIntoArrayLines(Lines);
	
	for (const FString& Line : Lines)
	{
		if (Line.StartsWith(TEXT("bAutoConnectOnStartup=")))
		{
			bAutoConnectOnStartup = Line.Contains(TEXT("True"));
		}
		else if (Line.StartsWith(TEXT("bRememberLastConnection=")))
		{
			bRememberLastConnection = Line.Contains(TEXT("True"));
		}
		else if (Line.StartsWith(TEXT("+SavedConnections=")))
		{
			// Parse format: +SavedConnections=(IPAddress="...",Port=...,bEnabled=...)
			FMoALiveLinkConnectionInfo Conn;
			
			FString TempStr = Line;
			TempStr.RemoveFromStart(TEXT("+SavedConnections="));
			TempStr.RemoveFromStart(TEXT("("));
			TempStr.RemoveFromEnd(TEXT(")"));
			
			// Parse IPAddress
			FString IPPart, Rest;
			if (TempStr.Split(TEXT(","), &IPPart, &Rest))
			{
				IPPart.RemoveFromStart(TEXT("IPAddress="));
				IPPart = IPPart.Replace(TEXT("\""), TEXT(""));
				Conn.IPAddress = IPPart;
				TempStr = Rest;
			}
			
			// Parse Port
			FString PortPart;
			if (TempStr.Split(TEXT(","), &PortPart, &Rest))
			{
				PortPart.RemoveFromStart(TEXT("Port="));
				Conn.Port = FCString::Atoi(*PortPart);
				TempStr = Rest;
			}
			
			// Parse bEnabled
			TempStr.RemoveFromStart(TEXT("bEnabled="));
			Conn.bEnabled = TempStr.Equals(TEXT("True"), ESearchCase::IgnoreCase);
			
			SavedConnections.Add(Conn);
			UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Loaded connection: %s:%d (Enabled: %d)"), *Conn.IPAddress, Conn.Port, Conn.bEnabled);
		}
	}
	
	UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Loaded %d connections from config"), SavedConnections.Num());
}

TArray<FIPv4Endpoint> UMoALiveLinkSettings::GetEnabledEndpoints() const
{
	TArray<FIPv4Endpoint> Endpoints;
	
	for (const FMoALiveLinkConnectionInfo& Connection : SavedConnections)
	{
		if (Connection.bEnabled)
		{
			Endpoints.Add(Connection.GetEndpoint());
			UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Found saved connection: %s:%d"), *Connection.IPAddress, Connection.Port);
		}
	}
	
	if (Endpoints.Num() == 0)
	{
		UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] No saved connections found"));
	}
	
	return Endpoints;
}

void UMoALiveLinkSettings::AddOrUpdateConnection(const FIPv4Endpoint& Endpoint)
{
	if (!bRememberLastConnection)
	{
		UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Remember connections disabled, not saving"));
		return;
	}

	FString NewIP = Endpoint.Address.ToString();
	int32 NewPort = Endpoint.Port;

	// Check if connection already exists
	for (FMoALiveLinkConnectionInfo& Connection : SavedConnections)
	{
		if (Connection.IPAddress == NewIP && Connection.Port == NewPort)
		{
			Connection.bEnabled = true;
			SaveConnectionsToConfig();
			UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Updated existing connection: %s:%d"), *NewIP, NewPort);
			return;
		}
	}

	// Add new connection
	FMoALiveLinkConnectionInfo NewConnection;
	NewConnection.IPAddress = NewIP;
	NewConnection.Port = NewPort;
	NewConnection.bEnabled = true;
	SavedConnections.Add(NewConnection);
	SaveConnectionsToConfig();

	UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Added new connection: %s:%d (Total: %d)"), *NewIP, NewPort, SavedConnections.Num());
}

void UMoALiveLinkSettings::RemoveConnection(const FIPv4Endpoint& Endpoint)
{
	FString RemoveIP = Endpoint.Address.ToString();
	int32 RemovePort = Endpoint.Port;

	for (int32 i = SavedConnections.Num() - 1; i >= 0; --i)
	{
		if (SavedConnections[i].IPAddress == RemoveIP && SavedConnections[i].Port == RemovePort)
		{
			SavedConnections.RemoveAt(i);
			SaveConnectionsToConfig();
			UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Removed connection: %s:%d (Remaining: %d)"), *RemoveIP, RemovePort, SavedConnections.Num());
			return;
		}
	}
	
	UE_LOG(LogTemp, Warning, TEXT("[MoA LiveLink] Connection not found to remove: %s:%d"), *RemoveIP, RemovePort);
}

void UMoALiveLinkSettings::ClearAllConnections()
{
	SavedConnections.Empty();
	SaveConnectionsToConfig();
	UE_LOG(LogTemp, Log, TEXT("[MoA LiveLink] Cleared all connections"));
}

FIPv4Endpoint UMoALiveLinkSettings::GetDefaultEndpoint() const
{
	// Return first saved connection, or fallback
	if (SavedConnections.Num() > 0)
	{
		return SavedConnections[0].GetEndpoint();
	}

	// Fallback for UI when no connections saved
	FIPv4Address Address;
	FIPv4Address::Parse(TEXT("127.0.0.1"), Address);
	return FIPv4Endpoint(Address, 7777);
}

#if WITH_EDITOR
void UMoALiveLinkSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);
	// Save when user edits properties in Project Settings UI
	SaveConnectionsToConfig();
}
#endif


