using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using CliFx;
using CliFx.Attributes;
using CliFx.Infrastructure;
using ZB.MOM.WW.GRAccess.Cli.GRAccess;
using ZB.MOM.WW.GRAccess.Cli.Protocol;
using ZB.MOM.WW.GRAccess.Cli.Session;

namespace ZB.MOM.WW.GRAccess.Cli.Commands.Session
{
    [Command("session start", Description = "Start a background GRAccess session")]
    public class SessionStartCommand : ICommand
    {
        [CommandOption("galaxy", 'g', Description = "Galaxy name", IsRequired = true)]
        public string GalaxyName { get; init; }

        [CommandOption("node", 'n', Description = "GR node name", IsRequired = true)]
        public string NodeName { get; init; }

        [CommandOption("idle-timeout", Description = "Idle timeout in minutes")]
        public int IdleTimeoutMinutes { get; init; } = 30;

        public async ValueTask ExecuteAsync(IConsole console)
        {
            var nodeName = GRAccessDiagnostics.NormalizeNodeName(NodeName);

            // Check if session already running
            var existing = SessionInfo.Load(GalaxyName);
            if (existing != null && existing.IsAlive())
            {
                await console.Output.WriteLineAsync(
                    $"Session already running for galaxy '{GalaxyName}' (PID {existing.ProcessId})")
                    .ConfigureAwait(false);
                return;
            }

            // Clean up stale session file
            existing?.Delete();

            // Launch self as background daemon
            var exePath = Assembly.GetExecutingAssembly().Location;
            var startInfo = new ProcessStartInfo
            {
                FileName = exePath,
                Arguments = $"--daemon --galaxy \"{GalaxyName}\" --node \"{nodeName}\" --idle-timeout {IdleTimeoutMinutes}",
                UseShellExecute = false,
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden
            };
            var process = Process.Start(startInfo);
            if (process == null)
                throw new InvalidOperationException("Failed to start session daemon process.");

            // Wait for daemon to become ready
            var deadline = DateTime.UtcNow.AddSeconds(90);
            bool ready = false;
            while (DateTime.UtcNow < deadline)
            {
                Thread.Sleep(500);
                if (SessionClient.TryConnect(GalaxyName, out var client))
                {
                    client.Dispose();
                    ready = true;
                    break;
                }

                // Check if daemon process exited early (connection failure, etc.)
                if (process.HasExited)
                {
                    throw new InvalidOperationException(
                        $"Daemon process exited with code {process.ExitCode}. Check logs for details.");
                }
            }

            if (ready)
            {
                await console.Output.WriteLineAsync(
                    $"Session started for galaxy '{GalaxyName}' (PID {process.Id})")
                    .ConfigureAwait(false);
            }
            else
            {
                throw new TimeoutException(
                    "Session daemon did not become ready within 90 seconds. Check logs for details.");
            }
        }
    }
}
