<?php

declare(strict_types=1);

namespace App\Domain\Shared\Infrastructure\ApiPlatform\Resource;

use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use App\Domain\Shared\Application\Response\JobResponse;
use App\Domain\Shared\Domain\Model\JobStatus;
use App\Domain\Shared\Infrastructure\ApiPlatform\State\Processor\DeleteJobProcessor;
use App\Domain\Shared\Infrastructure\ApiPlatform\State\Processor\DeleteJobsByCriteriaProcessor;
use App\Domain\Shared\Infrastructure\ApiPlatform\State\Provider\DeleteJobProvider;
use App\Domain\Shared\Infrastructure\ApiPlatform\State\Provider\GetJobListStateProvider;
use App\Domain\Shared\Infrastructure\ApiPlatform\State\Provider\GetJobStateProvider;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(
    shortName: 'Job',
    operations: [
        new GetCollection(
            uriTemplate: '/jobs',
            provider: GetJobListStateProvider::class,
            output: GetJobListResource::class,
            description: 'Liste des jobs',
            openapiContext: [
                'parameters' => [
                    [
                        'name' => 'status',
                        'in' => 'query',
                        'description' => 'Filtrer par status (séparés par des virgules pour plusieurs statuts, ex: "pending,in_progress" ou sous forme de tableau avec "status[]=")',
                        'required' => false,
                        'schema' => [
                            'oneOf' => [
                                [
                                    'type' => 'string',
                                    'example' => 'pending,in_progress'
                                ],
                                [
                                    'type' => 'array',
                                    'items' => [
                                        'type' => 'string',
                                        'enum' => ['pending', 'in_progress', 'completed', 'failed', 'cancelled']
                                    ],
                                    'example' => ['pending', 'in_progress']
                                ]
                            ]
                        ],
                        'style' => 'form',
                        'explode' => false
                    ],
                    [
                        'name' => 'type',
                        'in' => 'query',
                        'description' => 'Filtrer par type de job (ex: scraping_job)',
                        'required' => false,
                        'schema' => ['type' => 'string']
                    ],
                    [
                        'name' => 'createdAfter',
                        'in' => 'query',
                        'description' => 'Date de création minimum (format ISO8601)',
                        'required' => false,
                        'schema' => ['type' => 'string', 'format' => 'date-time']
                    ],
                    [
                        'name' => 'createdBefore',
                        'in' => 'query',
                        'description' => 'Date de création maximum (format ISO8601)',
                        'required' => false,
                        'schema' => ['type' => 'string', 'format' => 'date-time']
                    ],
                    [
                        'name' => 'page',
                        'in' => 'query',
                        'description' => 'Numéro de la page',
                        'required' => false,
                        'schema' => ['type' => 'integer', 'default' => 1, 'minimum' => 1]
                    ],
                    [
                        'name' => 'limit',
                        'in' => 'query',
                        'description' => 'Nombre d\'éléments par page',
                        'required' => false,
                        'schema' => ['type' => 'integer', 'default' => 20, 'minimum' => 1]
                    ],
                    [
                        'name' => 'sortBy',
                        'in' => 'query',
                        'description' => 'Champ de tri',
                        'required' => false,
                        'schema' => [
                            'type' => 'string',
                            'enum' => ['createdAt', 'type', 'status'],
                            'default' => 'createdAt'
                        ]
                    ],
                    [
                        'name' => 'sortOrder',
                        'in' => 'query',
                        'description' => 'Ordre de tri',
                        'required' => false,
                        'schema' => [
                            'type' => 'string',
                            'enum' => ['ASC', 'DESC'],
                            'default' => 'DESC'
                        ]
                    ]
                ]
            ]
        ),
        new Get(
            uriTemplate: '/jobs/{id}',
            provider: GetJobStateProvider::class,
            output: GetJobListResource::class,
            description: 'Récupère un job par son identifiant',
        ),
        new Delete(
            uriTemplate: '/jobs/{id}',
            provider: DeleteJobProvider::class,
            processor: DeleteJobProcessor::class,
            description: 'Supprime un job par son identifiant',
        ),
        new Delete(
            uriTemplate: '/jobs',
            processor: DeleteJobsByCriteriaProcessor::class,
            description: 'Supprime les jobs correspondant aux critères',
            openapiContext: [
                'parameters' => [
                    [
                        'name' => 'status',
                        'in' => 'query',
                        'description' => 'Filtrer par statut(s) (virgule-séparés ou tableau)',
                        'required' => false,
                        'schema' => ['type' => 'string'],
                    ],
                    [
                        'name' => 'type',
                        'in' => 'query',
                        'description' => 'Filtrer par type de job',
                        'required' => false,
                        'schema' => ['type' => 'string'],
                    ],
                    [
                        'name' => 'createdAfter',
                        'in' => 'query',
                        'description' => 'Date de création minimum (ISO8601)',
                        'required' => false,
                        'schema' => ['type' => 'string', 'format' => 'date-time'],
                    ],
                    [
                        'name' => 'createdBefore',
                        'in' => 'query',
                        'description' => 'Date de création maximum (ISO8601)',
                        'required' => false,
                        'schema' => ['type' => 'string', 'format' => 'date-time'],
                    ],
                ]
            ]
        ),
    ]
)]
class GetJobListResource
{
    public function __construct(
        #[ApiProperty(
            identifier: true,
            description: 'Identifiant unique du job'
        )]
        public readonly string $id,
        #[ApiProperty(description: 'Type du job (ex: scraping_job)')]
        #[Assert\NotBlank]
        public readonly string $type,
        #[ApiProperty(description: 'Status du job')]
        #[Assert\NotBlank]
        public readonly string $status,
        #[ApiProperty(description: 'Date de création du job')]
        #[Assert\NotNull]
        public readonly \DateTimeImmutable $createdAt,
        #[ApiProperty(description: 'Date de début d\'exécution du job')]
        public readonly ?\DateTimeImmutable $startedAt = null,
        #[ApiProperty(description: 'Date de fin d\'exécution du job')]
        public readonly ?\DateTimeImmutable $completedAt = null,
        #[ApiProperty(description: 'Raison de l\'échec si le job a échoué')]
        public readonly ?string $failureReason = null,
        #[ApiProperty(description: 'Nombre de tentatives effectuées')]
        #[Assert\GreaterThanOrEqual(0)]
        public readonly int $attempts = 0,
        #[ApiProperty(description: 'Nombre maximum de tentatives autorisées')]
        #[Assert\GreaterThan(0)]
        public readonly int $maxAttempts = 3,
        #[ApiProperty(description: 'Données contextuelles du job')]
        public readonly array $context = []
    ) {
    }

    public static function fromJob(\App\Domain\Shared\Domain\Model\Job $job): self
    {
        return new self(
            id: $job->id,
            type: $job->type,
            status: $job->status->value,
            createdAt: $job->createdAt,
            startedAt: $job->startedAt,
            completedAt: $job->completedAt,
            failureReason: $job->failureReason,
            attempts: $job->attempts,
            maxAttempts: $job->maxAttempts,
            context: $job->context
        );
    }

    public static function fromJobResponse(JobResponse $response): self
    {
        return new self(
            id: $response->id,
            type: $response->type,
            status: $response->status,
            createdAt: $response->createdAt,
            startedAt: $response->startedAt,
            completedAt: $response->completedAt,
            failureReason: $response->failureReason,
            attempts: $response->attempts,
            maxAttempts: $response->maxAttempts,
            context: $response->context
        );
    }
}
