// SPDX-FileCopyrightText: 2022 Frans van Dorsselaer
//
// SPDX-License-Identifier: GPL-3.0-only

using System.Diagnostics;
using System.Management.Automation;
using System.Runtime.Serialization.Json;
using System.Text;
using Usbipd.Automation;

namespace Usbipd.PowerShell;

[Cmdlet(VerbsCommon.Get, "UsbipdDevice")]
[OutputType(typeof(Device))]
public class GetUsbipdDeviceCommand : Cmdlet
{
    State State = new();

    protected override void BeginProcessing()
    {
        WriteDebug($"Detected installation path: {Installation.ExePath}");

        var startInfo = new ProcessStartInfo
        {
            FileName = Installation.ExePath,
            UseShellExecute = false,
            StandardOutputEncoding = Encoding.UTF8,
            StandardErrorEncoding = Encoding.UTF8,
            RedirectStandardInput = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true,
            Arguments = "state",
        };

        using var process = Process.Start(startInfo) ?? throw new ApplicationFailedException($"Cannot execute '{Installation.ExePath}'.");
        var stdout = string.Empty;
        var stderr = string.Empty;

        var captureTasks = new[]
        {
            Task.Run(async () => stdout = await process.StandardOutput.ReadToEndAsync()),
            Task.Run(async () => stderr = await process.StandardError.ReadToEndAsync()),
        };

        process.WaitForExit();
        Task.WhenAll(captureTasks).Wait();

        if (process.ExitCode != 0)
        {
            throw new ApplicationFailedException($"usbipd failed with exit code {process.ExitCode}.");
        }
        if (!string.IsNullOrEmpty(stderr))
        {
            throw new ApplicationFailedException($"usbipd returned unexpected error text:\n\n{stderr}");
        }

        WriteDebug(stdout);

        var serializer = new DataContractJsonSerializer(typeof(State));
        using var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(stdout));
        State = (State)serializer.ReadObject(memoryStream);
    }

    protected override void ProcessRecord()
    {
        foreach (var d in State.Devices)
        {
            WriteObject(d);
        }
    }
}
