<?php

declare(strict_types=1);

use App\Framework\Filesystem\SerializerRegistry;
use App\Framework\Filesystem\Serializers\JsonSerializer;
use App\Framework\Filesystem\Serializers\CsvSerializer;
use App\Framework\Filesystem\Serializers\PhpSerializer;
use App\Framework\Filesystem\Exceptions\SerializerNotFoundException;

describe('SerializerRegistry', function () {
    it('can register serializers', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        expect($registry->has('json'))->toBeTrue();
        expect($registry->get('json'))->toBe($jsonSerializer);
    });

    it('can set default serializer', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer, setAsDefault: true);

        expect($registry->hasDefault())->toBeTrue();
        expect($registry->getDefault())->toBe($jsonSerializer);
    });

    it('can get serializer by extension', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        $serializer = $registry->getByExtension('json');
        expect($serializer)->toBe($jsonSerializer);
    });

    it('throws exception when serializer not found by name', function () {
        $registry = new SerializerRegistry();

        try {
            $registry->get('nonexistent');
            expect(true)->toBeFalse('Should have thrown exception');
        } catch (SerializerNotFoundException $e) {
            expect($e)->toBeInstanceOf(SerializerNotFoundException::class);
        }
    });

    it('throws exception when serializer not found by extension', function () {
        $registry = new SerializerRegistry();

        try {
            $registry->getByExtension('xyz');
            expect(true)->toBeFalse('Should have thrown exception');
        } catch (SerializerNotFoundException $e) {
            expect($e)->toBeInstanceOf(SerializerNotFoundException::class);
        }
    });

    it('throws exception when no default serializer set', function () {
        $registry = new SerializerRegistry();

        try {
            $registry->getDefault();
            expect(true)->toBeFalse('Should have thrown exception');
        } catch (SerializerNotFoundException $e) {
            expect($e)->toBeInstanceOf(SerializerNotFoundException::class);
        }
    });

    it('can detect serializer from file path', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        $detected = $registry->detectFromPath('/path/to/file.json');
        expect($detected)->toBe($jsonSerializer);
    });

    it('throws exception when detecting from path without extension', function () {
        $registry = new SerializerRegistry();

        try {
            $registry->detectFromPath('/path/to/file');
            expect(true)->toBeFalse('Should have thrown exception');
        } catch (SerializerNotFoundException $e) {
            expect($e)->toBeInstanceOf(SerializerNotFoundException::class);
        }
    });

    it('can get serializer by MIME type', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        $serializer = $registry->getByMimeType('application/json');
        expect($serializer)->toBe($jsonSerializer);
    });

    it('throws exception when MIME type not found', function () {
        $registry = new SerializerRegistry();

        try {
            $registry->getByMimeType('application/unknown');
            expect(true)->toBeFalse('Should have thrown exception');
        } catch (SerializerNotFoundException $e) {
            expect($e)->toBeInstanceOf(SerializerNotFoundException::class);
        }
    });

    it('can list all registered serializers', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();
        $csvSerializer = new CsvSerializer();

        $registry->register('json', $jsonSerializer);
        $registry->register('csv', $csvSerializer);

        $serializers = $registry->all();

        expect($serializers)->toHaveCount(2);
        expect($serializers['json'])->toBe($jsonSerializer);
        expect($serializers['csv'])->toBe($csvSerializer);
    });

    it('can get registered serializer names', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();
        $csvSerializer = new CsvSerializer();

        $registry->register('json', $jsonSerializer);
        $registry->register('csv', $csvSerializer);

        $names = $registry->getSerializerNames();

        expect($names)->toHaveCount(2);
        expect($names)->toContain('json');
        expect($names)->toContain('csv');
    });

    it('can get statistics', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();
        $csvSerializer = new CsvSerializer();

        $registry->register('json', $jsonSerializer, setAsDefault: true);
        $registry->register('csv', $csvSerializer);

        $stats = $registry->getStats();

        expect($stats['total_serializers'])->toBe(2);
        expect($stats['default_serializer'])->toBe('json');
        expect($stats['supported_extensions'])->toHaveCount(2);
        expect($stats['supported_extensions'])->toContain('json');
        expect($stats['supported_extensions'])->toContain('csv');
    });

    it('creates default registry with common serializers', function () {
        $registry = SerializerRegistry::createDefault();

        expect($registry->has('json'))->toBeTrue();
        expect($registry->has('csv'))->toBeTrue();
        expect($registry->has('php'))->toBeTrue();
        expect($registry->hasDefault())->toBeTrue();
        expect($registry->getDefault())->toBeInstanceOf(JsonSerializer::class);
    });

    it('automatically maps extensions and MIME types on registration', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        // Extension mapping
        expect($registry->getByExtension('json'))->toBe($jsonSerializer);

        // MIME type mapping
        expect($registry->getByMimeType('application/json'))->toBe($jsonSerializer);
    });

    it('overrides default serializer when set multiple times', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();
        $csvSerializer = new CsvSerializer();

        $registry->register('json', $jsonSerializer, setAsDefault: true);
        $registry->register('csv', $csvSerializer, setAsDefault: true);

        expect($registry->getDefault())->toBe($csvSerializer);
    });

    it('detects serializer from path with multiple dots', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        $detected = $registry->detectFromPath('/path/to/file.backup.json');
        expect($detected)->toBe($jsonSerializer);
    });

    it('handles case-insensitive extension detection', function () {
        $registry = new SerializerRegistry();
        $jsonSerializer = new JsonSerializer();

        $registry->register('json', $jsonSerializer);

        $detected = $registry->detectFromPath('/path/to/file.JSON');
        expect($detected)->toBe($jsonSerializer);
    });
});
