<?php

declare(strict_types=1);

namespace App\Framework\ErrorReporting;

use DateTimeImmutable;

/**
 * Criteria for searching error reports
 */
final readonly class ErrorReportCriteria
{
    public function __construct(
        public ?DateTimeImmutable $from = null,
        public ?DateTimeImmutable $to = null,
        public ?array $levels = null,
        public ?array $exceptions = null,
        public ?array $routes = null,
        public ?array $methods = null,
        public ?string $userId = null,
        public ?string $environment = null,
        public ?array $tags = null,
        public ?string $search = null,
        public ?string $fingerprint = null,
        public ?int $minSeverity = null,
        public ?int $maxSeverity = null,
        public int $limit = 100,
        public int $offset = 0,
        public string $orderBy = 'timestamp',
        public string $orderDir = 'DESC'
    ) {
    }

    /**
     * Create criteria for recent errors
     */
    public static function recent(int $hours = 24): self
    {
        $from = (new DateTimeImmutable())->modify("-{$hours} hours");

        return new self(from: $from);
    }

    /**
     * Create criteria for critical errors
     */
    public static function critical(): self
    {
        return new self(
            levels: ['emergency', 'alert', 'critical'],
            maxSeverity: 2
        );
    }

    /**
     * Create criteria for errors by user
     */
    public static function byUser(string $userId): self
    {
        return new self(userId: $userId);
    }

    /**
     * Create criteria for errors by route
     */
    public static function byRoute(string $route): self
    {
        return new self(routes: [$route]);
    }

    /**
     * Create criteria for errors by exception type
     */
    public static function byException(string $exceptionClass): self
    {
        return new self(exceptions: [$exceptionClass]);
    }

    /**
     * Create criteria for production errors
     */
    public static function production(): self
    {
        return new self(environment: 'production');
    }

    /**
     * Create criteria with search term
     */
    public static function search(string $term): self
    {
        return new self(search: $term);
    }

    /**
     * Add time range filter
     */
    public function withTimeRange(DateTimeImmutable $from, DateTimeImmutable $to): self
    {
        return new self(
            from: $from,
            to: $to,
            levels: $this->levels,
            exceptions: $this->exceptions,
            routes: $this->routes,
            methods: $this->methods,
            userId: $this->userId,
            environment: $this->environment,
            tags: $this->tags,
            search: $this->search,
            fingerprint: $this->fingerprint,
            minSeverity: $this->minSeverity,
            maxSeverity: $this->maxSeverity,
            limit: $this->limit,
            offset: $this->offset,
            orderBy: $this->orderBy,
            orderDir: $this->orderDir
        );
    }

    /**
     * Add level filter
     */
    public function withLevels(array $levels): self
    {
        return new self(
            from: $this->from,
            to: $this->to,
            levels: $levels,
            exceptions: $this->exceptions,
            routes: $this->routes,
            methods: $this->methods,
            userId: $this->userId,
            environment: $this->environment,
            tags: $this->tags,
            search: $this->search,
            fingerprint: $this->fingerprint,
            minSeverity: $this->minSeverity,
            maxSeverity: $this->maxSeverity,
            limit: $this->limit,
            offset: $this->offset,
            orderBy: $this->orderBy,
            orderDir: $this->orderDir
        );
    }

    /**
     * Add environment filter
     */
    public function withEnvironment(string $environment): self
    {
        return new self(
            from: $this->from,
            to: $this->to,
            levels: $this->levels,
            exceptions: $this->exceptions,
            routes: $this->routes,
            methods: $this->methods,
            userId: $this->userId,
            environment: $environment,
            tags: $this->tags,
            search: $this->search,
            fingerprint: $this->fingerprint,
            minSeverity: $this->minSeverity,
            maxSeverity: $this->maxSeverity,
            limit: $this->limit,
            offset: $this->offset,
            orderBy: $this->orderBy,
            orderDir: $this->orderDir
        );
    }

    /**
     * Add pagination
     */
    public function withPagination(int $limit, int $offset = 0): self
    {
        return new self(
            from: $this->from,
            to: $this->to,
            levels: $this->levels,
            exceptions: $this->exceptions,
            routes: $this->routes,
            methods: $this->methods,
            userId: $this->userId,
            environment: $this->environment,
            tags: $this->tags,
            search: $this->search,
            fingerprint: $this->fingerprint,
            minSeverity: $this->minSeverity,
            maxSeverity: $this->maxSeverity,
            limit: $limit,
            offset: $offset,
            orderBy: $this->orderBy,
            orderDir: $this->orderDir
        );
    }

    /**
     * Add ordering
     */
    public function withOrdering(string $orderBy, string $orderDir = 'DESC'): self
    {
        return new self(
            from: $this->from,
            to: $this->to,
            levels: $this->levels,
            exceptions: $this->exceptions,
            routes: $this->routes,
            methods: $this->methods,
            userId: $this->userId,
            environment: $this->environment,
            tags: $this->tags,
            search: $this->search,
            fingerprint: $this->fingerprint,
            minSeverity: $this->minSeverity,
            maxSeverity: $this->maxSeverity,
            limit: $this->limit,
            offset: $this->offset,
            orderBy: $orderBy,
            orderDir: $orderDir
        );
    }

    /**
     * Convert to array for storage layer
     */
    public function toArray(): array
    {
        return [
            'from' => $this->from?->format('c'),
            'to' => $this->to?->format('c'),
            'levels' => $this->levels,
            'exceptions' => $this->exceptions,
            'routes' => $this->routes,
            'methods' => $this->methods,
            'user_id' => $this->userId,
            'environment' => $this->environment,
            'tags' => $this->tags,
            'search' => $this->search,
            'fingerprint' => $this->fingerprint,
            'min_severity' => $this->minSeverity,
            'max_severity' => $this->maxSeverity,
            'limit' => $this->limit,
            'offset' => $this->offset,
            'order_by' => $this->orderBy,
            'order_dir' => $this->orderDir,
        ];
    }
}
