<?php

declare(strict_types=1);

namespace App\Framework\FormGenerator;

use ReflectionClass;
use ReflectionProperty;

/**
 * Analysiert Request Object Properties und extrahiert Field Schema
 */
final readonly class RequestPropertyAnalyzer
{
    public function __construct(
        private FieldTypeResolver $typeResolver,
        private ValidationAttributeMapper $attributeMapper
    ) {
    }

    /**
     * Analyze Request Object and generate form schema
     */
    public function analyze(string $requestClass): RequestFormSchema
    {
        $reflection = new ReflectionClass($requestClass);
        $fields = [];

        foreach ($reflection->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
            $fields[] = $this->analyzeProperty($property);
        }

        return new RequestFormSchema(
            requestClass: $requestClass,
            fields: $fields
        );
    }

    /**
     * Analyze single property
     */
    private function analyzeProperty(ReflectionProperty $property): FormFieldSchema
    {
        // Get validation attributes
        $validationAttributes = $this->getValidationAttributes($property);

        // Resolve field type from PHP type + validation attributes
        $fieldType = $this->typeResolver->resolve($property, $validationAttributes);

        // Map validation attributes to HTML attributes
        $htmlAttributes = $this->attributeMapper->map($validationAttributes);

        // Check if required
        $required = $this->isRequired($property, $validationAttributes);

        // Get PHP type
        $phpType = $property->getType()?->getName() ?? 'mixed';

        return new FormFieldSchema(
            name: $property->getName(),
            phpType: $phpType,
            fieldType: $fieldType,
            validationAttributes: $validationAttributes,
            htmlAttributes: $htmlAttributes,
            required: $required
        );
    }

    /**
     * Get all validation rule attributes from property
     *
     * @return array<object>
     */
    private function getValidationAttributes(ReflectionProperty $property): array
    {
        $attributes = [];

        foreach ($property->getAttributes() as $attribute) {
            $attributeClass = $attribute->getName();

            // Check if it's a validation rule (in Validation\Rules namespace)
            if (str_contains($attributeClass, 'Validation\\Rules\\')) {
                $attributes[] = $attribute->newInstance();
            }
        }

        return $attributes;
    }

    /**
     * Check if field is required
     */
    private function isRequired(ReflectionProperty $property, array $validationAttributes): bool
    {
        // Check for Required attribute
        foreach ($validationAttributes as $attr) {
            if ($attr instanceof \App\Framework\Validation\Rules\Required) {
                return true;
            }
        }

        // Check if type is nullable
        $type = $property->getType();
        if ($type && ! $type->allowsNull()) {
            return true; // Non-nullable = required
        }

        return false;
    }
}
