<?php

/**
 * Shared helpers for fixed Vala-IR optimizer CLI passes.
 */
final class ValaIrOptimizerSupport
{
    /** Write a CLI error message to stderr, falling back to stdout. */
    public static function cliError(string $message): void
    {
        $stderr = fopen("php://stderr", "w");
        if ($stderr !== false) {
            fwrite($stderr, $message);
            fclose($stderr);
            return;
        }
        echo $message;
    }

    /** Write a red CLI warning to stderr when a caller decides one is needed. */
    public static function cliRedWarning(string $message): void
    {
        self::cliError("\033[31m" . $message . "\033[0m");
    }

    /** Convert an IR object to its debug array representation. */
    public static function toDebugArray(object $ir): array
    {
        if (!method_exists($ir, "toArray")) {
            throw new RuntimeException("Expected IR object with toArray(), got " . get_debug_type($ir));
        }
        return $ir->toArray();
    }

    /** Append a comment marker to a program object. */
    public static function appendMarker(object $ir, string $marker): object
    {
        if (!method_exists($ir, "withAppendedComment")) {
            throw new RuntimeException("Expected IR program with withAppendedComment(), got " . get_debug_type($ir));
        }

        return $ir->withAppendedComment(new ValaIrComment(
            "OptimizerMarker",
            $marker,
            0,
            0,
        ));
    }

    /** Print usage for a fixed optimizer CLI pass. */
    public static function usage(string $argv0, string $pass, array $allowedOptions = []): void
    {
        $options = $allowedOptions === [] ? '' : ' [' . implode('] [', $allowedOptions) . ']';
        self::cliError("Usage: {$argv0}{$options} <input.valair> <output.valair.afteropt.{$pass}>\n");
    }

    /** Read, optimize and write one fixed optimizer CLI pass. */
    public static function runFixedCli(array $argv, int $argc, string $pass, callable $optimizer, array $allowedOptions = []): void
    {
        $positionals = [];
        $options = [];
        $allowedOptionMap = array_fill_keys($allowedOptions, true);
        for ($i = 1; $i < $argc; $i++) {
            if (str_starts_with($argv[$i], "--")) {
                if (!isset($allowedOptionMap[$argv[$i]])) {
                    self::cliError("Unknown option: {$argv[$i]}\n");
                    exit(2);
                }
                $options[$argv[$i]] = true;
                continue;
            }
            $positionals[] = $argv[$i];
        }

        if (count($positionals) !== 2) {
            self::usage($argv[0], $pass, $allowedOptions);
            exit(2);
        }

        [$inputFile, $outputFile] = $positionals;
        $serializedIr = @file_get_contents($inputFile);
        if ($serializedIr === false) {
            self::cliError("Could not read input file: {$inputFile}\n");
            exit(1);
        }

        try {
            $ir = PhpSerializedBundle::unpack($serializedIr);
            $optimized = $optimizer($ir, $options);
            $serializedOptimized = PhpSerializedBundle::pack($optimized);
        } catch (Throwable $error) {
            self::cliError($error->getMessage() . "\n");
            exit(1);
        }

        if (file_put_contents($outputFile, $serializedOptimized) === false) {
            self::cliError("Could not write output file: {$outputFile}\n");
            exit(1);
        }

        echo "Wrote optimized Vala IR ({$pass}) to {$outputFile}\n";
    }
}
