import { ResultAsync } from "@shared/utils/resultasync.ts";
import { getMessageFromError } from "@shared/utils/result.ts";

const shellCmd = new Deno.Command("/bin/sh", {
    stdin: "piped",
    stdout: "piped",
    stderr: "piped",
});

class UsbipController {
    private shell = shellCmd.spawn();
    private stdinWriter = this.shell.stdin.getWriter();
    private stdoutReader = this.shell.stdout.pipeThrough(
        new TextDecoderStream(),
    ).getReader();
    private stderrReader = this.shell.stderr.pipeThrough(
        new TextDecoderStream(),
    ).getReader();
    private readonly encoder = new TextEncoder();
    private readonly marker = "___FINISHED___";

    constructor() {}

    run(cmd: string): ResultAsync<CommandOutput, string> {
        return ResultAsync.fromPromise(
            (async () => {
                cmd = `${cmd}\necho ${this.marker}\necho ${this.marker} >&2\n`;

                await this.stdinWriter.write(this.encoder.encode(
                    cmd,
                ));

                let outFinished = false, errFinished = false;
                let stdout = "", stderr = "";

                while (!outFinished || !errFinished) {
                    if (!outFinished) {
                        const { value } = await this.stdoutReader.read();
                        if (!outFinished) {
                            if (
                                value?.includes(this.marker)
                            ) {
                                stdout = stdout.trim();
                                outFinished = true;
                            } else {
                                stdout += value;
                            }
                        }
                    }
                    if (!errFinished) {
                        const { value } = await this.stderrReader.read();
                        if (!errFinished) {
                            if (
                                value?.includes(this.marker)
                            ) {
                                stderr = stderr.trim();
                                errFinished = true;
                            } else {
                                stderr += value;
                            }
                        }
                    }
                }

                return {
                    stdout: stdout.trim(),
                    stderr: stderr.trim(),
                };
            })(),
            (e) => getMessageFromError(e),
        );
    }
}

interface CommandOutput {
    stdout: string;
    stderr: string;
}

const usbip = new UsbipController();

let a = 0;

for (let i = 0; i < 100; i++) {
    const t = performance.now();
    console.log(await usbip.run("usbip list -l"));
    a += performance.now() - t;
}

console.log(a / 100);

//await usbip.run("usbip list -l");
//await usbip.run("usbip list -l");
//await usbip.run("usbip list -l");
//await usbip.run("usbip list -l");

//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();
//new Deno.Command("usbip", { args: ["list", "-l"] }).outputSync();

//const decoder = new TextDecoder();
//
//const now1 = new Date().getTime();
//
Deno.exit(0);
