<?php

namespace Daylight\Core\Modules\PageBuilder\Concerns;

use Daylight\Core\Modules\PageBuilder\Registries\ComponentRegistry;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

trait InteractsWithPageBuilder
{
    public function getPageBuilderRules(string $fieldName = 'components', bool $required = true): array
    {
        $rules = [
            $fieldName => $required ? ['required', 'array'] : ['sometimes', 'nullable'],
            $fieldName . '.*.id' => ['sometimes', 'nullable'],
            $fieldName . '.*.type' => ['required', 'string', 'max:255'],
            $fieldName . '.*.data' => ['required', 'array'],
        ];

        // Add field-specific validation based on component definitions
        $registry = app(ComponentRegistry::class);
        $components = $this->input($fieldName, []);

        if (is_string($components)) {
            $components = json_decode($components, true) ?: [];
        }

        // Ensure components is an array
        if (! is_array($components)) {
            $components = [];
        }

        foreach ($components as $index => $component) {
            if (! isset($component['type']) || ! is_array($component)) {
                continue;
            }

            $definition = $registry->getDefinition($component['type']);
            if (! $definition) {
                continue;
            }

            foreach ($definition->fields() as $field) {
                $fieldPath = "{$fieldName}.{$index}.data.{$field->name}";
                $fieldRules = [];

                $isRequired = isset($field->options['required']) && $field->options['required'];

                // Add type-specific rules
                switch ($field->type) {
                    case 'text':
                    case 'wysiwyg':
                        $fieldRules[] = $isRequired ? 'required' : 'nullable';
                        $fieldRules[] = 'string';
                        if (isset($field->options['max'])) {
                            $fieldRules[] = 'max:' . $field->options['max'];
                        }
                        break;

                    case 'select':
                        $fieldRules[] = $isRequired ? 'required' : 'nullable';
                        $fieldRules[] = 'string';
                        break;

                    case 'button':
                        $rules["{$fieldPath}.url"] = ['nullable', 'string', 'max:255'];
                        $rules["{$fieldPath}.label"] = ['nullable', 'string', 'max:255'];
                        break;

                    case 'media':
                        $fieldRules[] = $isRequired ? 'required' : 'nullable';
                        $fieldRules[] = 'array';

                        // If field is required, ensure at least one media item
                        if ($isRequired) {
                            $fieldRules[] = 'min:1';
                        }

                        if (isset($field->amountOfFiles) && $field->amountOfFiles === 1) {
                            $fieldRules[] = 'max:1';
                        }

                        // Only validate media IDs if they are present
                        $rules["{$fieldPath}.*.id"] = ['sometimes', 'required', 'exists:media,id'];
                        break;

                    case 'repeater':
                        $fieldRules[] = $isRequired ? 'required' : 'nullable';
                        $fieldRules[] = 'array';

                        // Add validation for repeater sub-fields
                        foreach ($field->items as $subField) {
                            $subFieldPath = "{$fieldPath}.*.{$subField->name}";
                            $subFieldRules = [];

                            $subIsRequired = isset($subField->options['required']) && $subField->options['required'];

                            if ($subField->type === 'media') {
                                $subFieldRules[] = $subIsRequired ? 'required' : 'nullable';
                                $subFieldRules[] = 'array';
                                if ($subIsRequired) {
                                    $subFieldRules[] = 'min:1';
                                }
                                // Only validate media IDs if they are present
                                $rules["{$subFieldPath}.*.id"] = ['sometimes', 'required', 'exists:media,id'];
                            } else {
                                $subFieldRules[] = $subIsRequired ? 'required' : 'nullable';
                                $subFieldRules[] = 'string';
                            }

                            $rules[$subFieldPath] = $subFieldRules;
                        }
                        break;

                    case 'related':
                        $fieldRules[] = $isRequired ? 'required' : 'nullable';
                        $fieldRules[] = 'array';

                        // Validate that each item has an ID
                        $rules["{$fieldPath}.*.id"] = ['required', 'integer'];
                        break;
                }

                if (! empty($fieldRules)) {
                    $rules[$fieldPath] = $fieldRules;
                }
            }
        }

        return $rules;
    }

    public function prepareForValidation(): void
    {
        // Support both JSON string (old Vue implementation) and array (new Livewire implementation)
        $components = $this->input('components');

        // Fallback to JSON fields if components data is missing or incomplete (e.g., after validation error)
        $jsonComponents = $this->input('components_json', []);
        if (! empty($jsonComponents) && is_array($jsonComponents)) {
            $componentsFromJson = [];
            foreach ($jsonComponents as $index => $jsonComponent) {
                if (is_string($jsonComponent)) {
                    $decoded = json_decode($jsonComponent, true);
                    if (is_array($decoded)) {
                        $componentsFromJson[$index] = $decoded;
                    }
                } elseif (is_array($jsonComponent)) {
                    $componentsFromJson[$index] = $jsonComponent;
                }
            }

            // If no components from form, use JSON as base
            if (empty($components) || ! is_array($components)) {
                $components = $componentsFromJson;
            } else {
                // Merge JSON data with form data: JSON provides structure, form provides values
                foreach ($componentsFromJson as $index => $jsonComponent) {
                    if (! isset($components[$index])) {
                        // Component doesn't exist in form data, use JSON version
                        $components[$index] = $jsonComponent;
                    } else {
                        // Deep merge: JSON provides base structure with all fields, form values override
                        if (isset($jsonComponent['data']) && isset($components[$index]['data'])) {
                            // Merge data arrays: form values take precedence
                            $components[$index]['data'] = array_merge($jsonComponent['data'], $components[$index]['data']);
                        }
                        // Ensure other fields from JSON are preserved if missing in form
                        $components[$index] = array_merge($jsonComponent, $components[$index]);
                    }
                }
                ksort($components);
            }
        }

        \Illuminate\Support\Facades\Log::info('prepareForValidation - RAW components', [
            'type' => gettype($components),
            'is_string' => is_string($components),
            'data' => $components,
        ]);

        if (is_string($components)) {
            $components = json_decode($components, true);
        }

        // Remove internal _uid field and normalize media fields
        if (is_array($components)) {
            $registry = app(\Daylight\Core\Modules\PageBuilder\Registries\ComponentRegistry::class);

            $components = collect($components)->map(function ($component) use ($registry) {
                // Skip invalid components
                if (! is_array($component) || ! isset($component['type'])) {
                    return null;
                }

                // Get component definition to identify media fields
                $definition = $registry->getDefinition($component['type']);

                if ($definition && isset($component['data']) && is_array($component['data'])) {
                    foreach ($definition->fields() as $field) {
                        $fieldName = $field->name;

                        \Illuminate\Support\Facades\Log::info('Checking field', [
                            'component_type' => $component['type'],
                            'field_name' => $fieldName,
                            'field_type' => $field->type,
                            'current_value' => $component['data'][$fieldName] ?? 'NOT_SET',
                            'value_type' => isset($component['data'][$fieldName]) ? gettype($component['data'][$fieldName]) : 'NOT_SET',
                        ]);

                        // Ensure media fields are always arrays
                        if ($field->type === 'media') {
                            $value = $component['data'][$fieldName] ?? null;

                            // Handle various empty states
                            if ($value === null || $value === '' || $value === '[]') {
                                $component['data'][$fieldName] = [];
                                \Illuminate\Support\Facades\Log::info('Converted media field to empty array', [
                                    'field_name' => $fieldName,
                                    'original_value' => $value,
                                ]);
                            }
                            // If it's a JSON string, decode it
                            elseif (is_string($value) && str_starts_with($value, '[')) {
                                $decoded = json_decode($value, true);
                                if (is_array($decoded)) {
                                    $component['data'][$fieldName] = $decoded;
                                    \Illuminate\Support\Facades\Log::info('Decoded JSON string for media field', [
                                        'field_name' => $fieldName,
                                        'original_value' => $value,
                                        'decoded_value' => $decoded,
                                    ]);
                                }
                            }
                        }

                        // Ensure related fields are always arrays (handle JSON from textarea)
                        if ($field->type === 'related') {
                            $value = $component['data'][$fieldName] ?? null;

                            // Handle various empty states
                            if ($value === null || $value === '' || $value === '[]') {
                                $component['data'][$fieldName] = [];
                            }
                            // If it's a JSON string, decode it
                            elseif (is_string($value) && str_starts_with($value, '[')) {
                                $decoded = json_decode($value, true);
                                if (is_array($decoded)) {
                                    $component['data'][$fieldName] = $decoded;
                                }
                            }
                        }

                        // Ensure repeater fields are arrays and normalize nested media
                        if ($field->type === 'repeater' && isset($component['data'][$fieldName]) && is_array($component['data'][$fieldName])) {
                            foreach ($component['data'][$fieldName] as $rowIndex => $row) {
                                if (is_array($row)) {
                                    foreach ($field->items as $subField) {
                                        if ($subField->type === 'media') {
                                            $subValue = $row[$subField->name] ?? null;

                                            // Handle various empty states
                                            if ($subValue === null || $subValue === '' || $subValue === '[]') {
                                                $component['data'][$fieldName][$rowIndex][$subField->name] = [];
                                            }
                                            // If it's a JSON string, decode it
                                            elseif (is_string($subValue) && str_starts_with($subValue, '[')) {
                                                $decoded = json_decode($subValue, true);
                                                if (is_array($decoded)) {
                                                    $component['data'][$fieldName][$rowIndex][$subField->name] = $decoded;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // Keep _uid for Livewire component tracking, but don't save it to database
                // We'll remove it in getComponentsFromRequest instead
                return $component;
            })->filter()->values()->toArray();
        }

        \Illuminate\Support\Facades\Log::info('prepareForValidation - AFTER normalization', [
            'components' => $components,
        ]);

        $this->merge([
            'components' => $components,
        ]);
    }

    public function getComponentsFromRequest(string $fieldName = 'components'): Collection
    {
        return collect($this->get($fieldName))
            ->map(function (array $component, $index) {
                return [
                    ...Arr::only($component, ['id', 'type', 'data']),
                    'order' => $index,
                ];
            })->values();
    }
}
