<?php

/**
 * Root node for the first Vala IR.
 */
final class ValaIrProgram
{
    private array $stmts;
    private array $uses;
    private string $phpSourceFile;
    private array $deferredHelpers;
    private array $comments;

    /**
     * Create a program from statement nodes and required Vala namespaces.
     */
    public function __construct(array $stmts, array $uses = [], string $phpSourceFile = '', array $deferredHelpers = [], array $comments = [])
    {
        $this->stmts = $stmts;
        $this->phpSourceFile = $phpSourceFile;
        $this->deferredHelpers = $deferredHelpers;
        $this->comments = $comments;
        $this->uses = array_values(array_unique(array_map(
            static fn (string $useName): string => $useName,
            $uses,
        )));
    }

    /**
     * Return a copy of this program with one root-level marker/comment appended.
     */
    public function withAppendedComment(ValaIrComment $comment): self
    {
        $comments = isset($this->comments) ? $this->comments : [];
        $comments[] = $comment;
        return new self($this->stmts, $this->uses, $this->phpSourceFile, $this->deferredHelpers, $comments);
    }

    /**
     * Return a copy of this program with replaced root statements.
     */
    public function withStmts(array $stmts): self
    {
        return new self($stmts, $this->uses, $this->phpSourceFile, $this->deferredHelpers, $this->comments);
    }

    /** Return this program's root statement nodes. */
    public function stmts(): array
    {
        return $this->stmts;
    }

    /**
     * Convert to a plain array for debugging/export.
     */
    public function toArray(): array
    {
        return [
            'format' => 'vala-ir-v0',
            'root' => [
                'kind' => 'Program',
                'phpSourceFile' => $this->phpSourceFile,
                'uses' => $this->uses,
                'stmts' => array_map(
                    static fn (object $stmt): array => method_exists($stmt, 'toArray') ? $stmt->toArray() : ['kind' => get_debug_type($stmt)],
                    $this->stmts,
                ),
                'deferredHelpers' => array_map(
                    static fn (object $helper): array => method_exists($helper, 'toArray') ? $helper->toArray() : ['kind' => get_debug_type($helper)],
                    $this->deferredHelpers,
                ),
                'comments' => array_map(static fn (ValaIrComment $comment): array => $comment->toArray(), isset($this->comments) ? $this->comments : []),
            ],
        ];
    }
}
