<?php

declare(strict_types=1);

namespace App\Framework\Console\Result;

use App\Framework\Console\ConsoleStyle;
use App\Framework\Console\ExitCode;

/**
 * Console Result Builder - Fluent API
 *
 * Provides a convenient fluent interface for building complex console results.
 * Automatically creates CompositeResult when multiple components are added.
 *
 * Example:
 *   return ConsoleResultBuilder::create()
 *       ->addText('System Report', ConsoleStyle::SUCCESS)
 *       ->addDivider()
 *       ->addTable(['Metric', 'Value'], [
 *           ['CPU', '45%'],
 *           ['Memory', '2.3GB']
 *       ])
 *       ->addNewLine()
 *       ->addText('Generated: ' . date('Y-m-d H:i:s'))
 *       ->withExitCode(ExitCode::SUCCESS)
 *       ->build();
 */
final class ConsoleResultBuilder
{
    /** @var array<ConsoleResult> */
    private array $results = [];

    private ExitCode $exitCode = ExitCode::SUCCESS;

    private function __construct()
    {
    }

    /**
     * Create new builder instance
     */
    public static function create(): self
    {
        return new self();
    }

    /**
     * Add text result
     */
    public function addText(
        string $message,
        ConsoleStyle $style = ConsoleStyle::INFO
    ): self {
        $this->results[] = new TextResult($message, $style, $this->exitCode);
        return $this;
    }

    /**
     * Add success text
     */
    public function addSuccess(string $message): self
    {
        $this->results[] = TextResult::success($message);
        return $this;
    }

    /**
     * Add error text
     */
    public function addError(string $message): self
    {
        $this->results[] = TextResult::error($message);
        $this->exitCode = ExitCode::FAILURE;
        return $this;
    }

    /**
     * Add warning text
     */
    public function addWarning(string $message): self
    {
        $this->results[] = TextResult::warning($message);
        return $this;
    }

    /**
     * Add info text
     */
    public function addInfo(string $message): self
    {
        $this->results[] = TextResult::info($message);
        return $this;
    }

    /**
     * Add plain text
     */
    public function addPlain(string $message): self
    {
        $this->results[] = TextResult::plain($message);
        return $this;
    }

    /**
     * Add table result
     *
     * @param array<string> $headers
     * @param array<array<string>> $rows
     */
    public function addTable(
        array $headers,
        array $rows,
        ?string $title = null
    ): self {
        $this->results[] = TableResult::create($headers, $rows, $title, $this->exitCode);
        return $this;
    }

    /**
     * Add divider (horizontal line)
     */
    public function addDivider(string $char = '─', int $length = 80): self
    {
        $this->results[] = TextResult::plain(str_repeat($char, $length));
        return $this;
    }

    /**
     * Add empty line
     */
    public function addNewLine(int $count = 1): self
    {
        for ($i = 0; $i < $count; $i++) {
            $this->results[] = TextResult::plain('');
        }
        return $this;
    }

    /**
     * Add existing result
     */
    public function addResult(ConsoleResult $result): self
    {
        $this->results[] = $result;
        return $this;
    }

    /**
     * Set exit code for builder
     *
     * Note: Individual results may override this
     */
    public function withExitCode(ExitCode $exitCode): self
    {
        $this->exitCode = $exitCode;
        return $this;
    }

    /**
     * Build final result
     *
     * Returns single result if only one component, CompositeResult otherwise
     */
    public function build(): ConsoleResult
    {
        if (empty($this->results)) {
            // Empty builder - return success with no output
            return TextResult::plain('');
        }

        if (count($this->results) === 1) {
            // Single result - return directly
            return $this->results[0];
        }

        // Multiple results - wrap in CompositeResult
        return new CompositeResult(...$this->results);
    }

    /**
     * Convenience: Build and render immediately
     */
    public function render(\App\Framework\Console\ConsoleOutputInterface $output): void
    {
        $this->build()->render($output);
    }
}
