<?php

namespace App\Tests\Service;

use App\Entity\PriceAutomatic;
use App\Repository\PriceAutomaticRepository;
use App\Service\MeilisearchService;
use App\Service\StripePriceService;
use App\Service\TarificationService;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;

class TarificationServiceTest extends TestCase
{
    public function testEnsureDefaultPricesCreatesAll(): void
    {
        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturn([]);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $created = $service->ensureDefaultPrices();

        $this->assertCount(19, $created);
        $this->assertContains('esite_business', $created);
        $this->assertContains('formation_heure', $created);
    }

    public function testEnsureDefaultPricesSkipsExisting(): void
    {
        $existing = new PriceAutomatic();
        $existing->setType('esite_business');
        $existing->setTitle('E-Site Basique');
        $existing->setPriceHt('500.00');

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturn([$existing]);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $created = $service->ensureDefaultPrices();

        $this->assertCount(18, $created);
        $this->assertNotContains('esite_business', $created);
    }

    public function testEnsureDefaultPricesNoneCreated(): void
    {
        $allExisting = [];
        foreach (TarificationService::getDefaultTypes() as $type => $data) {
            $p = new PriceAutomatic();
            $p->setType($type);
            $p->setTitle($data['title']);
            $p->setPriceHt($data['priceHt']);
            $allExisting[] = $p;
        }

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturn($allExisting);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $created = $service->ensureDefaultPrices();

        $this->assertSame([], $created);
    }

    public function testEnsureDefaultPricesWithMeilisearchAndStripe(): void
    {
        $p = new PriceAutomatic();
        $p->setType('esite_business');
        $p->setTitle('T');
        $p->setPriceHt('1.00');

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturnOnConsecutiveCalls([], [$p]);

        $em = $this->createStub(EntityManagerInterface::class);
        $meilisearch = $this->createStub(MeilisearchService::class);
        $stripe = $this->createStub(StripePriceService::class);

        $service = new TarificationService($repo, $em, null, $meilisearch, $stripe);
        $created = $service->ensureDefaultPrices();

        $this->assertCount(19, $created);
    }

    public function testEnsureDefaultPricesStripeError(): void
    {
        $price = new PriceAutomatic();
        $price->setType('esyweb_business');
        $price->setTitle('T');
        $price->setPriceHt('1.00');

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturnOnConsecutiveCalls([], [$price]);

        $em = $this->createStub(EntityManagerInterface::class);

        $stripe = $this->createStub(StripePriceService::class);
        $stripe->method('syncPrice')->willThrowException(new \RuntimeException('Stripe error'));

        $service = new TarificationService($repo, $em, null, null, $stripe);
        $created = $service->ensureDefaultPrices();

        $this->assertCount(19, $created);
    }

    public function testGetAll(): void
    {
        $prices = [new PriceAutomatic(), new PriceAutomatic()];

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturn($prices);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $this->assertCount(2, $service->getAll());
    }

    public function testGetByType(): void
    {
        $price = new PriceAutomatic();
        $price->setType('esyweb_business');
        $price->setTitle('T');
        $price->setPriceHt('1.00');

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findOneBy')->willReturn($price);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $this->assertSame($price, $service->getByType('esite_business'));
    }

    public function testGetByTypeNotFound(): void
    {
        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findOneBy')->willReturn(null);

        $em = $this->createStub(EntityManagerInterface::class);

        $service = new TarificationService($repo, $em);
        $this->assertNull($service->getByType('nonexistent'));
    }

    public function testGetDefaultTypes(): void
    {
        $types = TarificationService::getDefaultTypes();
        $this->assertCount(19, $types);
        $this->assertArrayHasKey('esite_business', $types);
        $this->assertArrayHasKey('title', $types['esite_business']);
    }

    public function testEnsureDefaultPricesStripeErrorWithLogger(): void
    {
        $price = new PriceAutomatic();
        $price->setType('ndd_depot');
        $price->setTitle('T');
        $price->setPriceHt('1.00');

        $repo = $this->createStub(PriceAutomaticRepository::class);
        $repo->method('findAll')->willReturnOnConsecutiveCalls([], [$price]);

        $em = $this->createStub(EntityManagerInterface::class);

        $logger = $this->createMock(\Psr\Log\LoggerInterface::class);
        $logger->expects($this->atLeastOnce())->method('error');

        $stripe = $this->createStub(StripePriceService::class);
        $stripe->method('syncPrice')->willThrowException(new \RuntimeException('Stripe error'));

        $service = new TarificationService($repo, $em, $logger, null, $stripe);
        $created = $service->ensureDefaultPrices();

        $this->assertCount(19, $created);
    }
}
