using System.Diagnostics;
using System.Drawing;

namespace Neta.Tray;

public sealed class TrayApplicationContext : ApplicationContext
{
    private readonly NotifyIcon _notifyIcon;
    private readonly BackendProcessManager _processManager;
    private readonly StatusClient _statusClient;
    private RuntimeBootstrapInfo? _runtime;
    private RuntimeStatusDto? _lastStatus;
    private bool _starting;

    public TrayApplicationContext()
        : this(new BackendProcessManager(), new StatusClient(new HttpClient()))
    {
    }

    internal TrayApplicationContext(BackendProcessManager processManager, StatusClient statusClient)
    {
        _processManager = processManager;
        _statusClient = statusClient;
        _notifyIcon = new NotifyIcon
        {
            Text = "Neta - 启动中…",
            Icon = SystemIcons.Application,
            Visible = true,
            ContextMenuStrip = new ContextMenuStrip()
        };

        _notifyIcon.ContextMenuStrip.Items.Add("打开系统", null, WrapAsync(OpenSystemAsync));
        _notifyIcon.ContextMenuStrip.Items.Add("重启服务", null, WrapAsync(RestartBackendAsync));
        _notifyIcon.ContextMenuStrip.Items.Add("停止服务", null, WrapAsync(StopBackendAsync));
        _notifyIcon.ContextMenuStrip.Items.Add("打开日志目录", null, (_, _) => OpenLogs());
        _notifyIcon.ContextMenuStrip.Items.Add("打开配置目录", null, (_, _) => OpenConfigDir());
        _notifyIcon.ContextMenuStrip.Items.Add("退出程序", null, WrapAsync(ExitAllAsync));

        _ = StartBackendSafe();
    }

    private EventHandler WrapAsync(Func<Task> action) => async (_, _) =>
    {
        try { await action(); }
        catch (Exception ex) { ShowError(ex.Message); }
    };

    private void ShowError(string message)
    {
        _notifyIcon.BalloonTipTitle = "Neta";
        _notifyIcon.BalloonTipText = message;
        _notifyIcon.BalloonTipIcon = ToolTipIcon.Error;
        _notifyIcon.ShowBalloonTip(5000);
    }

    private void MarkRunning()
    {
        _notifyIcon.Text = "Neta - 运行中";
    }

    private async Task StartBackendSafe()
    {
        try
        {
            await EnsureBackendAttachedAsync();
            MarkRunning();
        }
        catch (Exception ex)
        {
            _notifyIcon.Text = "Neta - 启动失败";
            ShowError($"后端启动失败: {ex.Message}");
        }
    }

    private async Task EnsureBackendAttachedAsync()
    {
        if (_starting) return;
        _starting = true;
        try
        {
            _runtime = RuntimeInfoStore.LoadFromInstalledConfig(AppContext.BaseDirectory);

            if (_runtime is not null)
            {
                var status = await _statusClient.GetStatusAsync(_runtime, CancellationToken.None);
                if (status is { Ready: true })
                {
                    _lastStatus = status;
                    MarkRunning();
                    return;
                }

                if (_processManager.IsBackendProcessAlive(_runtime.Pid))
                    return;
            }

            var traySecret = Guid.NewGuid().ToString("N");
            var backendExe = Path.Combine(AppContext.BaseDirectory, "backend.exe");
            _processManager.Start(backendExe, traySecret);
            _runtime = RuntimeInfoStore.WaitUntilAvailable(AppContext.BaseDirectory, TimeSpan.FromSeconds(30));
            _lastStatus = await _statusClient.GetStatusAsync(_runtime, CancellationToken.None);
            if (_lastStatus is not null)
            {
                MarkRunning();
            }
        }
        finally
        {
            _starting = false;
        }
    }

    private async Task OpenSystemAsync()
    {
        if (_lastStatus is null) await EnsureBackendAttachedAsync();
        if (_lastStatus is null) throw new InvalidOperationException("后端尚未就绪");
        MarkRunning();
        Process.Start(new ProcessStartInfo(_lastStatus.Url) { UseShellExecute = true });
    }

    private async Task RestartBackendAsync()
    {
        await StopBackendAsync();
        _lastStatus = null;
        _notifyIcon.Text = "Neta - 重启中…";
        await EnsureBackendAttachedAsync();
        _notifyIcon.Text = "Neta - 运行中";
    }

    private async Task StopBackendAsync()
    {
        var backendExePath = Path.Combine(AppContext.BaseDirectory, "backend.exe");
        _runtime ??= RuntimeInfoStore.LoadFromInstalledConfig(AppContext.BaseDirectory);
        if (_runtime is not null)
        {
            var pid = _runtime.Pid;
            var stoppedGracefully = false;
            try
            {
                await _statusClient.StopAsync(_runtime, CancellationToken.None);
                stoppedGracefully = true;
            }
            catch
            {
            }

            _processManager.WaitForExit(pid, TimeSpan.FromSeconds(10));
            if (_processManager.IsBackendProcessAlive(pid))
            {
                _processManager.KillProcess(pid);
            }
            _notifyIcon.Text = stoppedGracefully ? "Neta - 已停止" : "Neta - 已强制停止";
        }
        else
        {
            _notifyIcon.Text = "Neta - 已强制停止";
        }

        _processManager.KillInstalledBackendProcesses(backendExePath);
        _lastStatus = null;
        _runtime = null;
    }

    private async Task ExitAllAsync()
    {
        await StopBackendAsync();
        _notifyIcon.Visible = false;
        _notifyIcon.Dispose();
        ExitThread();
    }

    private void OpenLogs() => RuntimeInfoStore.OpenLogs(AppContext.BaseDirectory);

    private void OpenConfigDir() => RuntimeInfoStore.OpenConfigDir(AppContext.BaseDirectory);
}
