<?php

namespace App\Tests\Unit\Service;

use App\Service\Ingestion\IngestionService;
use App\Service\SentinelHub\SentinelHubClient;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;

class IngestionServiceTest extends TestCase
{
    private IngestionService $service;

    protected function setUp(): void
    {
        $this->service = new IngestionService(
            $this->createStub(SentinelHubClient::class),
            $this->createStub(EntityManagerInterface::class),
            new NullLogger(),
            sys_get_temp_dir(),
        );
    }

    // ── buildMultiPolygon ─────────────────────────────────────────────────────

    private function callBuildMultiPolygon(string $geojsonContent): ?array
    {
        $file = tempnam(sys_get_temp_dir(), 'phpunit_ingestion_') . '.geojson';
        file_put_contents($file, $geojsonContent);

        try {
            $method = new \ReflectionMethod(IngestionService::class, 'buildMultiPolygon');
            return $method->invoke($this->service, $file);
        } finally {
            @unlink($file);
        }
    }

    private static function makePolygon(int $points = 10, int $dn = 1): array
    {
        // Carré simple autour de 0,0 — répété $points fois pour avoir assez de coordonnées
        $coords = [];
        for ($i = 0; $i < $points; $i++) {
            $coords[] = [$i * 0.01, $i * 0.01];
        }
        $coords[] = $coords[0]; // fermer l'anneau

        return [
            'type'       => 'Feature',
            'properties' => ['DN' => $dn],
            'geometry'   => [
                'type'        => 'Polygon',
                'coordinates' => [$coords],
            ],
        ];
    }

    public function testReturnsNullWhenFileDoesNotExist(): void
    {
        $method = new \ReflectionMethod(IngestionService::class, 'buildMultiPolygon');
        $result = $method->invoke($this->service, '/tmp/nonexistent_phpunit.geojson');

        self::assertNull($result);
    }

    public function testReturnsNullForEmptyFeatureCollection(): void
    {
        $geojson = json_encode(['type' => 'FeatureCollection', 'features' => []]);
        self::assertNull($this->callBuildMultiPolygon($geojson));
    }

    public function testReturnsNullForInvalidJson(): void
    {
        self::assertNull($this->callBuildMultiPolygon('not-json'));
    }

    public function testReturnsNullWhenAllFeaturesHaveWrongDN(): void
    {
        $geojson = json_encode([
            'type'     => 'FeatureCollection',
            'features' => [self::makePolygon(10, 0), self::makePolygon(10, 2)],
        ]);
        self::assertNull($this->callBuildMultiPolygon($geojson));
    }

    public function testReturnsNullWhenPolygonHasTooFewPoints(): void
    {
        // MIN_RING_POINTS = 8 → 5 points doit être ignoré
        $geojson = json_encode([
            'type'     => 'FeatureCollection',
            'features' => [self::makePolygon(5, 1)],
        ]);
        self::assertNull($this->callBuildMultiPolygon($geojson));
    }

    public function testReturnMultiPolygonForValidFeature(): void
    {
        $geojson = json_encode([
            'type'     => 'FeatureCollection',
            'features' => [self::makePolygon(10, 1)],
        ]);
        $result = $this->callBuildMultiPolygon($geojson);

        self::assertNotNull($result);
        self::assertSame('MultiPolygon', $result['type']);
        self::assertCount(1, $result['coordinates']);
    }

    public function testHandlesMultipleValidFeatures(): void
    {
        $geojson = json_encode([
            'type'     => 'FeatureCollection',
            'features' => [
                self::makePolygon(10, 1),
                self::makePolygon(12, 1),
                self::makePolygon(5,  1), // trop petit → ignoré
            ],
        ]);
        $result = $this->callBuildMultiPolygon($geojson);

        self::assertNotNull($result);
        self::assertCount(2, $result['coordinates']); // 2 valides sur 3
    }

    public function testHandlesMultiPolygonGeometryType(): void
    {
        $coords1 = array_fill(0, 11, [0.0, 0.0]);
        $coords1[] = $coords1[0];
        $coords2 = array_fill(0, 11, [1.0, 1.0]);
        $coords2[] = $coords2[0];

        $feature = [
            'type'       => 'Feature',
            'properties' => ['DN' => 1],
            'geometry'   => [
                'type'        => 'MultiPolygon',
                'coordinates' => [[$coords1], [$coords2]],
            ],
        ];

        $geojson = json_encode(['type' => 'FeatureCollection', 'features' => [$feature]]);
        $result  = $this->callBuildMultiPolygon($geojson);

        self::assertNotNull($result);
        self::assertSame('MultiPolygon', $result['type']);
        self::assertCount(2, $result['coordinates']);
    }

    public function testIgnoresFeaturesWithDNZeroAndKeepsOthers(): void
    {
        $geojson = json_encode([
            'type'     => 'FeatureCollection',
            'features' => [
                self::makePolygon(10, 0), // DN=0 → ignoré
                self::makePolygon(10, 1), // valide
            ],
        ]);
        $result = $this->callBuildMultiPolygon($geojson);

        self::assertNotNull($result);
        self::assertCount(1, $result['coordinates']);
    }
}
