<?php

declare(strict_types=1);

namespace App\Framework\TypeCaster\Casters;

use App\Framework\TypeCaster\TypeCasterInterface;
use InvalidArgumentException;

/**
 * Universal UUID caster for various UUID-based Value Objects
 * Supports standard UUIDs and any class that has UUID-like behavior
 */
final readonly class UuidCaster implements TypeCasterInterface
{
    public function fromString(string $value): object
    {
        if (empty($value)) {
            throw new InvalidArgumentException('UUID value cannot be empty');
        }

        // Validate UUID format
        if (! preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $value)) {
            throw new InvalidArgumentException('Invalid UUID format: ' . $value);
        }

        // For now, return as generic class - specific implementations can override
        return new class ($value) {
            public function __construct(public readonly string $value)
            {
            }

            public function __toString(): string
            {
                return $this->value;
            }
        };
    }

    public function toString(mixed $value): string
    {
        if (is_string($value)) {
            return $value;
        }

        if (is_object($value)) {
            // Try common UUID Value Object methods
            if (method_exists($value, 'toString')) {
                return $value->toString();
            }
            if (method_exists($value, '__toString')) {
                return $value->__toString();
            }
            if (property_exists($value, 'value')) {
                return (string) $value->value;
            }
        }

        throw new InvalidArgumentException('Cannot convert value to UUID string');
    }

    public function supports(string $type): bool
    {
        // Don't support ULID types - they have their own caster
        if (str_contains($type, 'Ulid') || str_contains($type, 'ULID')) {
            return false;
        }

        // Only support explicit UUID types to avoid false matches
        // Support types that explicitly mention UUID or are known UUID Value Objects
        if (str_contains($type, 'UUID') || str_contains($type, 'Uuid')) {
            return true;
        }

        // Don't support generic types or anything ending just in "Id" - too broad
        // Specific Value Objects like UserId, ProductId etc. should have their own casters
        return false;
    }

    public function getPattern(): string
    {
        return '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';
    }
}
