<?php

declare(strict_types=1);

namespace App\Framework\Audit\ValueObjects;

use DateTimeImmutable;

/**
 * Audit query filter value object
 */
final readonly class AuditQuery
{
    public function __construct(
        public ?AuditableAction $action = null,
        public ?string $entityType = null,
        public ?string $entityId = null,
        public ?string $userId = null,
        public ?bool $success = null,
        public ?DateTimeImmutable $startDate = null,
        public ?DateTimeImmutable $endDate = null,
        public int $limit = 100,
        public int $offset = 0
    ) {
    }

    public static function all(): self
    {
        return new self();
    }

    public static function forAction(AuditableAction $action): self
    {
        return new self(action: $action);
    }

    public static function forEntity(string $entityType, ?string $entityId = null): self
    {
        return new self(entityType: $entityType, entityId: $entityId);
    }

    public static function forUser(string $userId): self
    {
        return new self(userId: $userId);
    }

    public static function failedOnly(): self
    {
        return new self(success: false);
    }

    public static function successfulOnly(): self
    {
        return new self(success: true);
    }

    public static function inDateRange(DateTimeImmutable $start, DateTimeImmutable $end): self
    {
        return new self(startDate: $start, endDate: $end);
    }

    public function withAction(AuditableAction $action): self
    {
        return new self(
            action: $action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withEntityType(string $entityType): self
    {
        return new self(
            action: $this->action,
            entityType: $entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withEntityId(string $entityId): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withUserId(string $userId): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withSuccess(bool $success): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withDateRange(DateTimeImmutable $start, DateTimeImmutable $end): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $start,
            endDate: $end,
            limit: $this->limit,
            offset: $this->offset
        );
    }

    public function withLimit(int $limit): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $limit,
            offset: $this->offset
        );
    }

    public function withOffset(int $offset): self
    {
        return new self(
            action: $this->action,
            entityType: $this->entityType,
            entityId: $this->entityId,
            userId: $this->userId,
            success: $this->success,
            startDate: $this->startDate,
            endDate: $this->endDate,
            limit: $this->limit,
            offset: $offset
        );
    }
}
