<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Tests\Unit;

use OCA\Mitgliederverwaltung\BackgroundJob\CalendarFullSyncJob;
use OCA\Mitgliederverwaltung\Service\CalendarSyncService;
use OCP\AppFramework\Utility\ITimeFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class CalendarFullSyncJobTest extends TestCase {

    private CalendarSyncService&MockObject $calendarSyncService;
    private LoggerInterface&MockObject $logger;
    private ITimeFactory&MockObject $timeFactory;
    private CalendarFullSyncJob $job;

    protected function setUp(): void {
        parent::setUp();

        $this->calendarSyncService = $this->createMock(CalendarSyncService::class);
        $this->logger = $this->createMock(LoggerInterface::class);
        $this->timeFactory = $this->createMock(ITimeFactory::class);

        $this->job = new CalendarFullSyncJob(
            $this->timeFactory,
            $this->calendarSyncService,
            $this->logger
        );
    }

    public function testConstruction(): void {
        $this->assertInstanceOf(CalendarFullSyncJob::class, $this->job);
    }

    public function testRunCallsFullSync(): void {
        $this->calendarSyncService->expects($this->once())
            ->method('fullSync')
            ->willReturn(['created' => 5, 'updated' => 3, 'deleted' => 1]);

        $this->logger->expects($this->once())
            ->method('info')
            ->with(
                'Calendar full sync completed',
                $this->callback(function (array $context) {
                    return $context['created'] === 5
                        && $context['updated'] === 3
                        && $context['deleted'] === 1
                        && $context['app'] === 'mitgliederverwaltung';
                })
            );

        $reflection = new \ReflectionMethod($this->job, 'run');
        $reflection->setAccessible(true);
        $reflection->invoke($this->job, []);
    }

    public function testRunLogsErrorOnException(): void {
        $exception = new \RuntimeException('Sync failed');

        $this->calendarSyncService->expects($this->once())
            ->method('fullSync')
            ->willThrowException($exception);

        $this->logger->expects($this->once())
            ->method('error')
            ->with(
                'Calendar full sync failed',
                $this->callback(function (array $context) use ($exception) {
                    return $context['exception'] === $exception
                        && $context['app'] === 'mitgliederverwaltung';
                })
            );

        $reflection = new \ReflectionMethod($this->job, 'run');
        $reflection->setAccessible(true);
        $reflection->invoke($this->job, []);
    }

    public function testRunHandlesZeroChanges(): void {
        $this->calendarSyncService->expects($this->once())
            ->method('fullSync')
            ->willReturn(['created' => 0, 'updated' => 0, 'deleted' => 0]);

        $this->logger->expects($this->once())
            ->method('info');

        $reflection = new \ReflectionMethod($this->job, 'run');
        $reflection->setAccessible(true);
        $reflection->invoke($this->job, []);
    }
}
