using System.Diagnostics;
using System.Text.Json;
using YamlDotNet.RepresentationModel;

namespace Neta.Tray;

public sealed class RuntimeBootstrapInfo
{
    public string DataDir { get; set; } = string.Empty;
    public string ControlBaseUrl { get; set; } = string.Empty;
    public string ControlSecret { get; set; } = string.Empty;
    public int Pid { get; set; }
    public bool Ready { get; set; }
}

public static class RuntimeInfoStore
{
    public static RuntimeBootstrapInfo ParseConfigAndRuntimeInfo(string configYaml, string runtimeInfoJson)
    {
        var dataDir = GetDataDirFromConfigYaml(configYaml);
        var runtime = JsonSerializer.Deserialize<RuntimeBootstrapInfo>(runtimeInfoJson, new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        })!;
        runtime.DataDir = dataDir;
        return runtime;
    }

    public static RuntimeBootstrapInfo? LoadFromInstalledConfig(string baseDirectory)
    {
        var configPath = Path.Combine(baseDirectory, "config.yaml");
        if (!File.Exists(configPath)) return null;

        var configYaml = File.ReadAllText(configPath);
        var dataDir = GetDataDirFromConfigYaml(configYaml);
        var runtimeInfoPath = Path.Combine(dataDir, "runtime-info.json");
        if (!File.Exists(runtimeInfoPath)) return null;

        return ParseConfigAndRuntimeInfo(configYaml, File.ReadAllText(runtimeInfoPath));
    }

    public static RuntimeBootstrapInfo WaitUntilAvailable(string baseDirectory, TimeSpan timeout)
    {
        var deadline = DateTime.UtcNow + timeout;
        while (DateTime.UtcNow < deadline)
        {
            var loaded = LoadFromInstalledConfig(baseDirectory);
            if (loaded is not null) return loaded;
            Thread.Sleep(200);
        }
        throw new TimeoutException("等待 runtime-info.json 超时");
    }

    public static bool HasRuntimeLock(string baseDirectory)
    {
        var configPath = Path.Combine(baseDirectory, "config.yaml");
        if (!File.Exists(configPath)) return false;

        var dataDir = GetDataDirFromConfigYaml(File.ReadAllText(configPath));
        return File.Exists(Path.Combine(dataDir, "neta.lock"));
    }

    public static void OpenLogs(string baseDirectory)
    {
        var runtime = LoadFromInstalledConfig(baseDirectory);
        if (runtime is null) return;
        Process.Start(new ProcessStartInfo(Path.Combine(runtime.DataDir, "logs")) { UseShellExecute = true });
    }

    public static void OpenConfigDir(string baseDirectory)
    {
        Process.Start(new ProcessStartInfo(baseDirectory) { UseShellExecute = true });
    }

    private static string GetDataDirFromConfigYaml(string configYaml)
    {
        using var input = new StringReader(configYaml);
        var yaml = new YamlStream();
        yaml.Load(input);
        var root = (YamlMappingNode)yaml.Documents[0].RootNode;
        return ((YamlScalarNode)((YamlMappingNode)root.Children[new YamlScalarNode("data")]).Children[new YamlScalarNode("dir")]).Value!.Replace("\\\\", "\\");
    }
}
