<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Tests\Export\Cronjob;

use Chill\MainBundle\Entity\CronJobExecution;
use Chill\MainBundle\Entity\ExportGeneration;
use Chill\MainBundle\Export\Cronjob\RemoveExpiredExportGenerationCronJob;
use Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Argument;
use Symfony\Component\Clock\MockClock;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Chill\MainBundle\Repository\ExportGenerationRepository;

/**
 * @internal
 *
 * @coversNothing
 */
class RemoveExpiredExportGenerationCronJobTest extends TestCase
{
    use ProphecyTrait;

    public function testCanRunReturnsTrueWhenLastExecutionIsNull()
    {
        $clock = new MockClock(new \DateTimeImmutable('2024-06-25 10:00:00'));
        $repo = $this->prophesize(ExportGenerationRepository::class);
        $bus = $this->prophesize(MessageBusInterface::class);

        $cronJob = new RemoveExpiredExportGenerationCronJob(
            $clock,
            $repo->reveal(),
            $bus->reveal()
        );

        $this->assertTrue($cronJob->canRun(null));
    }

    public function testCanRunReturnsTrueWhenLastStartIsOlderThan24Hours()
    {
        $clock = new MockClock(new \DateTimeImmutable('2024-06-25 10:00:00'));
        $repo = $this->prophesize(ExportGenerationRepository::class);
        $bus = $this->prophesize(MessageBusInterface::class);

        $cronJob = new RemoveExpiredExportGenerationCronJob(
            $clock,
            $repo->reveal(),
            $bus->reveal()
        );

        $execution = new CronJobExecution('remove-expired-export-generation');
        $execution->setLastStart(new \DateTimeImmutable('2024-06-24 09:59:59'));

        $this->assertTrue($cronJob->canRun($execution));
    }

    public function testCanRunReturnsFalseWhenLastStartIsWithin24Hours()
    {
        $clock = new MockClock(new \DateTimeImmutable('2024-06-25 10:00:00'));
        $repo = $this->prophesize(ExportGenerationRepository::class);
        $bus = $this->prophesize(MessageBusInterface::class);

        $cronJob = new RemoveExpiredExportGenerationCronJob(
            $clock,
            $repo->reveal(),
            $bus->reveal()
        );

        $execution = new CronJobExecution('remove-expired-export-generation');
        $execution->setLastStart(new \DateTimeImmutable('2024-06-24 10:01:00'));

        $this->assertFalse($cronJob->canRun($execution));
    }

    public function testRunDispatchesMessagesForExpiredExportsAndReturnsLastDeletion()
    {
        $clock = new MockClock(new \DateTimeImmutable('2024-06-25 11:21:00'));
        $repo = $this->prophesize(ExportGenerationRepository::class);
        $bus = $this->prophesize(MessageBusInterface::class);

        $expiredExports = [
            new ExportGeneration('dummy', []),
        ];

        $repo->findExpiredExportGeneration(Argument::that(fn ($dateTime) =>
            // Ensure the repository is called with the current clock time
            $dateTime instanceof \DateTimeImmutable
            && $dateTime->getTimestamp() === $clock->now()->getTimestamp()))->willReturn($expiredExports);

        // Expect one RemoveExportGenerationMessage for each expired export
        $bus->dispatch(Argument::that(fn (Envelope $envelope) => $envelope->getMessage() instanceof RemoveExportGenerationMessage))
            ->shouldBeCalledTimes(1)
            ->will(fn ($args) => $args[0]);

        $cronJob = new RemoveExpiredExportGenerationCronJob(
            $clock,
            $repo->reveal(),
            $bus->reveal()
        );

        $result = $cronJob->run([]);

        $this->assertIsArray($result);
        $this->assertEquals(['last-deletion' => $clock->now()->getTimestamp()], $result);
    }
}
