using System.Text.Json;
using System.Text.Json.Nodes;
using ArtificersScrollwork.Sidecar.Parsing;
using ArtificersScrollwork.Sidecar.Gumps;

/// <summary>
/// Entry point for the ASW C# sidecar.
/// Reads newline-delimited JSON requests from stdin, writes responses to stdout.
///
/// Request:  { "id": "uuid", "command": "cmd_name", "args": { ... } }
/// Response: { "id": "uuid", "ok": true, "data": { ... } }
///          | { "id": "uuid", "ok": false, "error": "message" }
/// </summary>

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
    WriteIndented = false,
};

ScriptIndexer? indexer = null;
CallChainTracer? tracer = null;

while (true)
{
    var line = Console.ReadLine();
    if (line is null) break;

    JsonObject? request;
    try { request = JsonSerializer.Deserialize<JsonObject>(line, options); }
    catch { continue; }
    if (request is null) continue;

    var id = request["id"]?.GetValue<string>() ?? "";
    var command = request["command"]?.GetValue<string>() ?? "";
    var reqArgs = request["args"] as JsonObject ?? new JsonObject();

    try
    {
        JsonNode? data = command switch
        {
            "index_scripts" => HandleIndexScripts(reqArgs),
            "get_class"     => HandleGetClass(reqArgs),
            "trace_method"  => HandleTraceMethod(reqArgs),
            "extract_gump"  => HandleExtractGump(reqArgs),
            "search"        => HandleSearch(reqArgs),
            _               => throw new InvalidOperationException($"Unknown command: {command}"),
        };

        WriteResponse(id, true, data, null, options);
    }
    catch (Exception ex)
    {
        WriteResponse(id, false, null, ex.Message, options);
    }
}

// ── Command handlers ──────────────────────────────────────────────────────────

JsonNode HandleIndexScripts(JsonObject args)
{
    var path = args["path"]?.GetValue<string>()
        ?? throw new ArgumentException("Missing 'path' argument");

    indexer = new ScriptIndexer();
    var index = indexer.IndexDirectory(path);

    // Build a compilation for the tracer
    tracer = new CallChainTracer(indexer.Compilation
        ?? throw new InvalidOperationException("Compilation not available after indexing"));

    return JsonSerializer.SerializeToNode(index, options)!;
}

JsonNode HandleGetClass(JsonObject args)
{
    EnsureIndexer();
    var className = args["class"]?.GetValue<string>()
        ?? throw new ArgumentException("Missing 'class' argument");

    var info = indexer!.GetClass(className)
        ?? throw new KeyNotFoundException($"Class '{className}' not found in index");

    return JsonSerializer.SerializeToNode(info, options)!;
}

JsonNode HandleTraceMethod(JsonObject args)
{
    EnsureIndexer();

    if (tracer is null)
        throw new InvalidOperationException("Tracer not initialized — send index_scripts first");

    var className = args["class"]?.GetValue<string>()
        ?? throw new ArgumentException("Missing 'class' argument");
    var methodName = args["method"]?.GetValue<string>()
        ?? throw new ArgumentException("Missing 'method' argument");

    var flowNode = tracer.TraceMethod(className, methodName);
    return JsonSerializer.SerializeToNode(flowNode, options)!;
}

JsonNode HandleExtractGump(JsonObject args)
{
    EnsureIndexer();
    throw new NotImplementedException("extract_gump not yet implemented (Phase 4)");
}

JsonNode HandleSearch(JsonObject args)
{
    EnsureIndexer();
    var query = args["query"]?.GetValue<string>()
        ?? throw new ArgumentException("Missing 'query' argument");

    var results = indexer!.Search(query);
    return JsonSerializer.SerializeToNode(results, options)!;
}

void EnsureIndexer()
{
    if (indexer is null)
        throw new InvalidOperationException("Scripts not indexed — send index_scripts first");
}

static void WriteResponse(string id, bool ok, JsonNode? data, string? error, JsonSerializerOptions opts)
{
    var response = new JsonObject
    {
        ["id"] = id,
        ["ok"] = ok,
    };

    if (ok && data is not null)
        response["data"] = data;
    else if (!ok)
        response["error"] = error ?? "Unknown error";

    Console.WriteLine(JsonSerializer.Serialize(response, opts));
    Console.Out.Flush();
}
