<?php

declare(strict_types=1);

namespace App\Framework\Router\Result;

use App\Framework\Http\Status;
use App\Framework\Pagination\ValueObjects\PaginationResponse;
use App\Framework\Router\ActionResult;

/**
 * API Data Result
 *
 * Standardized API response with data and optional metadata.
 * Supports both paginated and simple data responses.
 *
 * Response Structure (Paginated):
 * {
 *   "data": [...],
 *   "meta": {
 *     "result_count": 10,
 *     "limit": 10,
 *     "has_more": true,
 *     "current_page": 1,
 *     "total_pages": 5,
 *     ...
 *   },
 *   "timestamp": "2024-01-20T10:30:00Z"
 * }
 *
 * Response Structure (Simple):
 * {
 *   "data": {...},
 *   "meta": {...},
 *   "timestamp": "2024-01-20T10:30:00Z"
 * }
 */
final readonly class ApiDataResult implements ActionResult
{
    /**
     * @param PaginationResponse|array<mixed>|mixed $data Response data
     * @param array<string, mixed>|null $additionalMeta Additional metadata
     */
    private function __construct(
        public PaginationResponse|array $data,
        public ?array $additionalMeta = null,
        public Status $status = Status::OK
    ) {}

    /**
     * Create with pagination support (uses framework's PaginationResponse)
     */
    public static function paginated(
        PaginationResponse $paginationResponse,
        ?array $additionalMeta = null,
        Status $status = Status::OK
    ): self {
        return new self(
            data: $paginationResponse,
            additionalMeta: $additionalMeta,
            status: $status
        );
    }

    /**
     * Create simple data response without pagination
     *
     * @param mixed $data
     * @param array<string, mixed>|null $meta
     */
    public static function simple(
        mixed $data,
        ?array $meta = null,
        Status $status = Status::OK
    ): self {
        return new self(
            data: ['data' => $data],
            additionalMeta: $meta,
            status: $status
        );
    }

    /**
     * Create from array data
     *
     * @param array<mixed> $data
     * @param array<string, mixed>|null $meta
     */
    public static function fromArray(
        array $data,
        ?array $meta = null,
        Status $status = Status::OK
    ): self {
        return new self(
            data: ['data' => $data],
            additionalMeta: $meta,
            status: $status
        );
    }

    /**
     * Check if response is paginated
     */
    public function isPaginated(): bool
    {
        return $this->data instanceof PaginationResponse;
    }

    /**
     * Convert to array for JSON serialization
     */
    public function toArray(): array
    {
        if ($this->isPaginated()) {
            /** @var PaginationResponse $paginationResponse */
            $paginationResponse = $this->data;
            $response = $paginationResponse->toArray();

            // Merge additional meta if provided
            if ($this->additionalMeta !== null) {
                $response['meta'] = array_merge(
                    $response['meta'],
                    $this->additionalMeta
                );
            }
        } else {
            $response = $this->data;

            // Add meta section for simple responses
            if ($this->additionalMeta !== null || !isset($response['meta'])) {
                $response['meta'] = $this->additionalMeta ?? [];
            }
        }

        // Add timestamp to response
        $response['timestamp'] = (new \DateTimeImmutable())->format(\DateTimeInterface::RFC3339);

        return $response;
    }
}
