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

#pragma once

#include "CoreMinimal.h"
#include "AssetThumbnail.h"
#include "Input/Reply.h"
#include "Misc/Optional.h"
#include "SourcifyCore.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Views/SListView.h"

class SCompoundWidget;

class SSourcifyResults : public SCompoundWidget
{
public:
	SLATE_BEGIN_ARGS(SSourcifyResults)
	{
		_OwnerTab = nullptr;
		_SourcifyCore = nullptr;
	}

	SLATE_ARGUMENT(SDockTab*, OwnerTab)
	SLATE_ARGUMENT(const Sourcify::Results*, SourcifyResults)
	SLATE_ARGUMENT(Sourcify::ISourcifyCore*, SourcifyCore)
	SLATE_END_ARGS()

	void Construct(const FArguments& InArgs);

public:

	struct FIniReference
	{
		FString Ini;
		FString Section;
		FString Key;
	};

	struct FPackageReference
    {
        TObjectPtr<UPackage> PackagePtr;
        TOptional<FString> SourcifiedClassName;
        bool bIsDeleted = false;
        
        // Cached display data (populated on first row generation, used after deletion)
        bool bDisplayDataCached = false;
        FString CachedDisplayName;
        FString CachedPathName;
        FLinearColor CachedAssetTypeColor;
        TSharedPtr<FAssetThumbnail> CachedThumbnail;
        TWeakObjectPtr<UObject> CachedAsset;
    };

	struct FErrorReference
    {
		FString Error;
    };

	struct FCompilationErrorReference
	{
		TObjectPtr<UPackage> PackagePtr;
		FString BlueprintName;
	};

	// A single function rename entry
	struct FRenameReference
	{
		FString OriginalName;
		FString NewName;
		FString ConflictingParentClassName;
		FString ConflictingParentHeaderPath;
		int32 ConflictingParentLineNumber;
	};

	// A class group containing its rename entries
	struct FRenameClassGroup
	{
		FString ClassName;
		TArray<TSharedPtr<FRenameReference>> Renames;
	};

	using ResultsWindowIniReference = TPair<FString, TArray<SSourcifyResults::FIniReference>>;

protected:
	FReply OnCopyToClipboardButtonClick();
	FReply OnUndoButtonClick();
	FReply OnDeleteAllUnreferencedButtonClick();

	TSharedPtr<FAssetThumbnail> MakeAssetThumbnail(FLinearColor& OutAssetColor, FAssetThumbnailConfig& OutThumbnailConfig, UObject* InObject);

	/** Returns the visibility of the Undo button based on whether there are compilation errors */
	EVisibility GetUndoButtonVisibility() const;
	
	/** Returns the visibility of the Delete All button based on whether there are packages that should be deleted */
	EVisibility GetDeleteAllButtonVisibility() const;
	
	/** Checks if a package can be deleted (not referenced by assets outside PackagesThatShouldBeDeleted) */
	bool CanDeletePackage(TSharedPtr<FPackageReference> InPackage) const;
	
	/** Checks for dirty packages and prompts user to save. Calls OnComplete with true if ready to proceed, false if cancelled. */
	void PromptToSaveDirtyPackagesAsync(TFunction<void(bool bSuccess)> OnComplete);
	
	/** Performs the actual deletion of a single package (called after save/delay) */
	void ExecuteDeleteSinglePackage(TSharedPtr<FPackageReference> InPackage);
	
	/** Performs the actual deletion of multiple packages (called after save/delay) */
	void ExecuteDeleteMultiplePackages(const TArray<TSharedPtr<FPackageReference>>& PackagesToDelete);
	
	/** Deletes a single package */
	void DeleteSinglePackage(TSharedPtr<FPackageReference> InPackage);
	
	/** Gets the list of packages that can be safely deleted */
	TArray<TSharedPtr<FPackageReference>> GetDeletablePackages() const;

protected:
	// These are the ini references that are still using the non-sourcified asset and require manual fix-up
	// The key is the non-sourcified asset path
	TArray<TSharedPtr<ResultsWindowIniReference>> NonSourcifiedAssetIniReferences;
	
	// BPs that were Sourcified, thus reparented to C++ classes
    TArray<TSharedPtr<FPackageReference>> SourcifiedBPs;
	
	// Assets that contain references that were updated to newly Sourcified types
    TArray<TSharedPtr<FPackageReference>> PackagesContainingSourcifiedReferences;
	
	// Assets that were fully sourcified and should be deleted (enums and structs)
    TArray<TSharedPtr<FPackageReference>> PackagesThatShouldBeDeleted;
	
	// List view widget for packages that should be deleted (for refreshing after individual deletions)
	TSharedPtr<SListView<TSharedPtr<FPackageReference>>> PackagesThatShouldBeDeletedListView;
	
	// Errors that occurred during sourcification
    TArray<TSharedPtr<FErrorReference>> SourcificationErrors;

	// Errors that occurred during sourcification
    TArray<TSharedPtr<FErrorReference>> SourcificationWarnings;

	// Blueprints that failed to compile after sourcification
	TArray<TSharedPtr<FCompilationErrorReference>> BlueprintsWithCompilationErrors;

	// Function renames grouped by class
	TArray<FRenameClassGroup> RenameClassGroups;

	// Sourcification results to be copied to the system clipboard
	FString OutputLog;

	// All packages that were touched during Sourcification (for reload during undo)
	TArray<TObjectPtr<UPackage>> AllTouchedPackages;

private:
	SDockTab* ParentTab = nullptr;
	Sourcify::ISourcifyCore* SourcifyCore = nullptr;
	bool UndoPerformed = false;
};
