<?php

namespace Daylight\Core\Modules\PageBuilder\Livewire;

use Daylight\Core\Modules\PageBuilder\Entities\Field;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Livewire\Attributes\Modelable;
use Livewire\Component;

class PageBuilder extends Component
{
    #[Modelable]
    public array $components = [];

    public array $availableComponents = [];

    public string $name = 'components';

    public array $collapsed = [];

    public function mount($components = [], $availableComponents = [], string $name = 'components'): void
    {
        $this->components = $components instanceof Collection ? $components->toArray() : (array) $components;
        $this->availableComponents = $this->normalizeAvailableComponents(
            $availableComponents instanceof Collection ? $availableComponents->toArray() : (array) $availableComponents
        );
        $this->name = $name;

        // Add UIDs to existing components
        $this->components = collect($this->components)->map(function ($component, $index) {
            if (! isset($component['_uid'])) {
                $component['_uid'] = 'comp-' . uniqid() . '-' . $index;
            }

            return $component;
        })->toArray();

        // Normalize component data
        foreach ($this->components as &$component) {
            $component = $this->normalizeComponentData($component);
        }
    }

    protected function normalizeAvailableComponents(array $components): array
    {
        return collect($components)->map(function ($component) {
            // Ensure it's an array
            $component = is_array($component) ? $component : (array) $component;

            // Normalize fields if they exist
            if (isset($component['fields'])) {
                $component['fields'] = $this->normalizeFields($component['fields']);
            }

            return $component;
        })->toArray();
    }

    protected function normalizeFields($fields): array
    {
        if ($fields instanceof Collection) {
            $fields = $fields->toArray();
        }

        if (! is_array($fields)) {
            $fields = (array) $fields;
        }

        return collect($fields)->map(function ($field) {
            return $this->normalizeField($field);
        })->toArray();
    }

    protected function normalizeField($field): array
    {
        // If it's a Field object, use its toArray method
        if ($field instanceof Field) {
            return $field->toArray();
        }

        // Convert object to array
        if (is_object($field) && ! $field instanceof Collection) {
            $field = (array) $field;
        }

        if ($field instanceof Collection) {
            $field = $field->toArray();
        }

        if (! is_array($field)) {
            return [];
        }

        $normalized = [
            'type' => $field['type'] ?? null,
            'name' => $field['name'] ?? null,
            'label' => $field['label'] ?? null,
            'options' => $field['options'] ?? [],
            'selectOptions' => $field['selectOptions'] ?? [],
            'items' => [],
        ];

        // Add optional fields
        if (isset($field['relatedType'])) {
            $normalized['relatedType'] = $field['relatedType'];
        }
        if (isset($field['amountOfFiles'])) {
            $normalized['amountOfFiles'] = $field['amountOfFiles'];
        }

        // Recursively normalize nested items (for repeater fields)
        if (isset($field['items']) && ! empty($field['items'])) {
            $normalized['items'] = $this->normalizeFields($field['items']);
        }

        return $normalized;
    }

    public function addComponent(string $type): void
    {
        $definition = collect($this->availableComponents)->firstWhere('type', $type);

        if (! $definition) {
            return;
        }

        $component = [
            '_uid' => 'comp-' . uniqid() . '-' . count($this->components),
            'id' => null,
            'type' => $type,
            'data' => $this->getDefaultFieldData($definition['fields'] ?? []),
        ];

        $this->components[] = $this->normalizeComponentData($component);
    }

    public function deleteComponent(string $uid): void
    {
        $this->components = collect($this->components)
            ->reject(fn ($component) => ($component['_uid'] ?? null) === $uid)
            ->values()
            ->toArray();
    }

    public function reorderComponents(array $order): void
    {
        $reordered = [];
        foreach ($order as $uid) {
            $component = collect($this->components)->firstWhere('_uid', $uid);
            if ($component) {
                $reordered[] = $component;
            }
        }

        // Set new order
        $this->components = $reordered;

        // Normalize component data after reordering to ensure all fields are properly structured
        foreach ($this->components as &$component) {
            $component = $this->normalizeComponentData($component);
        }

        // Force Livewire to update by reassigning the property with re-indexed array
        // This ensures wire:model bindings are synchronized with the new indices
        $this->components = array_values($this->components);
    }

    public function toggleCollapse(string $uid): void
    {
        $this->collapsed[$uid] = ! ($this->collapsed[$uid] ?? false);
    }

    public function addRepeaterRow(string $componentUid, string $fieldName): void
    {
        $componentIndex = collect($this->components)->search(fn ($c) => ($c['_uid'] ?? null) === $componentUid);

        if ($componentIndex === false) {
            return;
        }

        $component = $this->components[$componentIndex] ?? null;
        if (! $component) {
            return;
        }

        $definition = collect($this->availableComponents)->firstWhere('type', $component['type']);
        $field = collect($definition['fields'] ?? [])->firstWhere('name', $fieldName);

        if (! $field || $field['type'] !== 'repeater') {
            return;
        }

        $newRow = $this->getDefaultFieldData($field['items'] ?? []);
        $this->components[$componentIndex]['data'][$fieldName][] = $newRow;
    }

    public function deleteRepeaterRow(string $componentUid, string $fieldName, int $rowIndex): void
    {
        $componentIndex = collect($this->components)->search(fn ($c) => ($c['_uid'] ?? null) === $componentUid);

        if ($componentIndex === false) {
            return;
        }

        if (isset($this->components[$componentIndex]['data'][$fieldName][$rowIndex])) {
            unset($this->components[$componentIndex]['data'][$fieldName][$rowIndex]);
            $this->components[$componentIndex]['data'][$fieldName] = array_values($this->components[$componentIndex]['data'][$fieldName]);
        }
    }

    protected function getDefaultFieldData(array $fields): array
    {
        $data = [];

        foreach ($fields as $field) {
            $fieldArray = is_array($field) ? $field : (array) $field;

            match ($fieldArray['type'] ?? null) {
                'repeater' => $data[$fieldArray['name']] = [],
                'button' => $data[$fieldArray['name']] = ['url' => null, 'label' => null],
                'media' => $data[$fieldArray['name']] = [],
                'select' => $data[$fieldArray['name']] = $this->getFirstSelectOption($fieldArray),
                'form' => $data[$fieldArray['name']] = null,
                default => $data[$fieldArray['name']] = null,
            };
        }

        return $data;
    }

    protected function getFirstSelectOption(array $fieldArray): ?string
    {
        $selectOptions = $fieldArray['selectOptions'] ?? [];

        if (empty($selectOptions)) {
            return null;
        }

        return (string) array_key_first($selectOptions);
    }

    protected function normalizeComponentData(array $component): array
    {
        $definition = collect($this->availableComponents)->firstWhere('type', $component['type']);

        if (! $definition) {
            return $component;
        }

        foreach ($definition['fields'] ?? [] as $field) {
            $fieldArray = is_array($field) ? $field : (array) $field;
            $fieldName = $fieldArray['name'];

            if (! isset($component['data'][$fieldName])) {
                match ($fieldArray['type'] ?? null) {
                    'repeater' => $component['data'][$fieldName] = [],
                    'button' => $component['data'][$fieldName] = ['url' => null, 'label' => null],
                    'media' => $component['data'][$fieldName] = [],
                    'select' => $component['data'][$fieldName] = $this->getFirstSelectOption($fieldArray),
                    default => $component['data'][$fieldName] = null,
                };
            }

            // Ensure button fields are objects
            if ($fieldArray['type'] === 'button' && ! is_array($component['data'][$fieldName])) {
                $component['data'][$fieldName] = ['url' => null, 'label' => null];
            }

            // Ensure media and repeater fields are arrays
            if (in_array($fieldArray['type'], ['media', 'repeater']) && ! is_array($component['data'][$fieldName])) {
                $component['data'][$fieldName] = [];
            }
        }

        return $component;
    }

    public function setMediaForField(int $componentIndex, string $fieldName, array $media): void
    {
        if (! isset($this->components[$componentIndex])) {
            return;
        }

        $this->components[$componentIndex]['data'][$fieldName] = $media;
    }

    public function setRepeaterMediaForField(int $componentIndex, string $fieldName, int $rowIndex, string $subFieldName, array $media): void
    {
        if (! isset($this->components[$componentIndex]['data'][$fieldName][$rowIndex])) {
            return;
        }

        $this->components[$componentIndex]['data'][$fieldName][$rowIndex][$subFieldName] = $media;
    }

    public function searchRelatedItems(string $relatedType, string $query, array $excludeIds = []): array
    {
        if (strlen($query) < 2) {
            return [];
        }

        if (! class_exists($relatedType) || ! method_exists($relatedType, 'searchForRelation')) {
            return [];
        }

        return $relatedType::searchForRelation($query, $excludeIds, 10)->toArray();
    }

    public function addRelatedItem(int $componentIndex, string $fieldName, array $item): void
    {
        if (! isset($this->components[$componentIndex])) {
            return;
        }

        $existing = $this->components[$componentIndex]['data'][$fieldName] ?? [];

        if (collect($existing)->contains('id', $item['id'])) {
            return;
        }

        $this->components[$componentIndex]['data'][$fieldName][] = $item;
    }

    public function removeRelatedItem(int $componentIndex, string $fieldName, int $itemIndex): void
    {
        if (! isset($this->components[$componentIndex]['data'][$fieldName][$itemIndex])) {
            return;
        }

        unset($this->components[$componentIndex]['data'][$fieldName][$itemIndex]);
        $this->components[$componentIndex]['data'][$fieldName] = array_values(
            $this->components[$componentIndex]['data'][$fieldName]
        );
    }

    public function reorderRelatedItems(int $componentIndex, string $fieldName, array $orderedIds): void
    {
        if (! isset($this->components[$componentIndex])) {
            return;
        }

        $items = $this->components[$componentIndex]['data'][$fieldName] ?? [];
        $reordered = [];

        foreach ($orderedIds as $id) {
            $item = collect($items)->firstWhere('id', (int) $id);
            if ($item) {
                $reordered[] = $item;
            }
        }

        $this->components[$componentIndex]['data'][$fieldName] = $reordered;
    }

    public function getComponentDefinition(string $type): ?array
    {
        return collect($this->availableComponents)->firstWhere('type', $type);
    }

    public function render(): View
    {
        return view('daylight::livewire.page-builder.page-builder');
    }
}
