<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Batch;

/**
 * Batch Result Value Object
 *
 * Represents the result of a single operation in a batch.
 *
 * Success Response:
 * {
 *   "success": true,
 *   "operationId": "op-1",
 *   "html": "<div>...</div>",  // OR fragments
 *   "fragments": {"counter": "<span>5</span>"},
 *   "state": {"count": 5},
 *   "events": []
 * }
 *
 * Error Response:
 * {
 *   "success": false,
 *   "operationId": "op-2",
 *   "error": "Action method not found",
 *   "errorCode": "ACTION_NOT_FOUND"
 * }
 */
final readonly class BatchResult
{
    /**
     * @param bool $success - Operation success status
     * @param string|null $operationId - Optional operation ID from request
     * @param string|null $html - Full HTML (if no fragments)
     * @param array|null $fragments - Fragment map {name: html}
     * @param array|null $state - Component state
     * @param array $events - Component events
     * @param string|null $error - Error message (if failed)
     * @param string|null $errorCode - Error code (if failed)
     */
    public function __construct(
        public bool $success,
        public ?string $operationId = null,
        public ?string $html = null,
        public ?array $fragments = null,
        public ?array $state = null,
        public array $events = [],
        public ?string $error = null,
        public ?string $errorCode = null
    ) {
    }

    /**
     * Create successful result
     */
    public static function success(
        ?string $operationId = null,
        ?string $html = null,
        ?array $fragments = null,
        ?array $state = null,
        array $events = []
    ): self {
        return new self(
            success: true,
            operationId: $operationId,
            html: $html,
            fragments: $fragments,
            state: $state,
            events: $events
        );
    }

    /**
     * Create failed result
     */
    public static function failure(
        string $error,
        string $errorCode = 'OPERATION_FAILED',
        ?string $operationId = null
    ): self {
        return new self(
            success: false,
            operationId: $operationId,
            error: $error,
            errorCode: $errorCode
        );
    }

    /**
     * Check if result has fragments
     */
    public function hasFragments(): bool
    {
        return $this->fragments !== null && ! empty($this->fragments);
    }

    /**
     * Check if result has full HTML
     */
    public function hasHtml(): bool
    {
        return $this->html !== null;
    }

    /**
     * Convert to array for JSON response
     */
    public function toArray(): array
    {
        if (! $this->success) {
            return array_filter([
                'success' => false,
                'operation_id' => $this->operationId,
                'error' => $this->error,
                'error_code' => $this->errorCode,
            ], fn ($value) => $value !== null);
        }

        return array_filter([
            'success' => true,
            'operation_id' => $this->operationId,
            'html' => $this->html,
            'fragments' => $this->fragments,
            'state' => $this->state,
            'events' => $this->events,
        ], fn ($value) => $value !== null && $value !== []);
    }
}
