// Copyright (c) 2026 HD Media. MIT licensed - see LICENSE.
//
// inspect_blueprint - return parent class, declared variables, function/event
// graph names of a Blueprint asset.
//
// UE 5.7 surface used (header:line citations for reviewer traceability):
//   Blueprint.h:412  -- UClass* ParentClass (inherited from UBlueprint)
//   Blueprint.h:504  -- TEnumAsByte<EBlueprintStatus> Status (UBlueprint member, public)
//
// Error format: free-form OutError strings (legacy surface — predates the canonical
// "<tool_name>: <error_code>: <detail>" convention used by later handlers). Migration
// is deferred; bridge consumers treat OutError as human-readable text rather than
// parsing for a code prefix.

#include "MCP/MCPHandler.h"

#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"

namespace
{
    // Mirrors Handler_InspectWidgetBlueprint.cpp's status->string helper
    // (UE 5.7, Blueprint.h:504). Enumerates the full EBlueprintStatus
    // value set explicitly — BS_MAX is a sentinel, not a state, so the default
    // arm is reserved for genuinely unknown values (forward-compatibility with
    // future engine enum additions).
    //
    // Surfaced by the PR #174 100-tool scorecard follow-up #4: the synthetic
    // audit_blueprint_compile_status reads result["blueprint_status"] from
    // this handler and buckets by status. Until this field landed, every
    // scanned BP fell into the "Unknown" bucket regardless of its real
    // compile state.
    //
    // Per-file unique name: UE 5.1 buckets unity builds differently than 5.7
    // and merges the three Inspect*Blueprint TUs into one unity blob, causing
    // an anonymous-namespace ODR clash among the identically-named helpers.
    // Unique per-file names are version-agnostic; behavior is unchanged.
    static FString BlueprintStatusToString_InspectBP(EBlueprintStatus Status)
    {
        switch (Status)
        {
        case BS_UpToDate:
            return TEXT("UpToDate");
        case BS_UpToDateWithWarnings:
            return TEXT("UpToDateWithWarnings");
        case BS_Dirty:
            return TEXT("Dirty");
        case BS_Error:
            return TEXT("Error");
        case BS_BeingCreated:
            return TEXT("BeingCreated");
        case BS_Unknown:
        default:
            return TEXT("Unknown");
        }
    }
}

class FHandler_InspectBlueprint : public IUCMCPHandler
{
public:
    virtual FString GetMethodName() const override { return TEXT("inspect_blueprint"); }

    virtual TSharedPtr<FJsonObject> Handle(const TSharedPtr<FJsonObject>& Params, FString& OutError) override
    {
        FString Path;
        if (!Params.IsValid() || !Params->TryGetStringField(TEXT("path"), Path))
        {
            OutError = TEXT("Missing required string param: 'path'");
            return nullptr;
        }

        UBlueprint* BP = LoadObject<UBlueprint>(nullptr, *Path);
        if (!BP)
        {
            OutError = FString::Printf(TEXT("Blueprint not found at path: %s"), *Path);
            return nullptr;
        }

        TSharedPtr<FJsonObject> Out = MakeShared<FJsonObject>();
        Out->SetStringField(TEXT("path"), Path);
        Out->SetStringField(TEXT("parent_class"), BP->ParentClass ? BP->ParentClass->GetName() : TEXT(""));
        Out->SetStringField(TEXT("blueprint_class"), BP->GetClass()->GetName());
        Out->SetStringField(TEXT("blueprint_status"), BlueprintStatusToString_InspectBP(static_cast<EBlueprintStatus>(BP->Status.GetValue())));

        TArray<TSharedPtr<FJsonValue>> Vars;
        for (const FBPVariableDescription& V : BP->NewVariables)
        {
            const TSharedRef<FJsonObject> J = MakeShared<FJsonObject>();
            J->SetStringField(TEXT("name"), V.VarName.ToString());
            J->SetStringField(TEXT("type_category"), V.VarType.PinCategory.ToString());
            J->SetStringField(TEXT("type_subcategory"), V.VarType.PinSubCategory.ToString());
            J->SetStringField(TEXT("default"), V.DefaultValue);
            Vars.Add(MakeShared<FJsonValueObject>(J));
        }
        Out->SetArrayField(TEXT("variables"), Vars);

        TArray<TSharedPtr<FJsonValue>> FuncGraphs;
        for (UEdGraph* G : BP->FunctionGraphs)
        {
            if (G) FuncGraphs.Add(MakeShared<FJsonValueString>(G->GetName()));
        }
        Out->SetArrayField(TEXT("function_graphs"), FuncGraphs);

        TArray<TSharedPtr<FJsonValue>> EventGraphs;
        for (UEdGraph* G : BP->UbergraphPages)
        {
            if (G) EventGraphs.Add(MakeShared<FJsonValueString>(G->GetName()));
        }
        Out->SetArrayField(TEXT("event_graphs"), EventGraphs);

        return Out;
    }
};

TSharedRef<IUCMCPHandler> Make_Handler_InspectBlueprint()
{
    return MakeShared<FHandler_InspectBlueprint>();
}
