<?php

namespace App\Http\Resources;

use App\Traits\IconForType;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;
use Mtc\ContentManager\Contracts\MediaUse;
use Mtc\ContentManager\Http\Resources\GlobalContentElementView as BaseGlobalContentElementView;
use Mtc\ContentManager\Http\Resources\MediaEntryResource;
use Mtc\ContentManager\Models\ContentElementField;
use Mtc\MercuryDataModels\ContentElement;

class GlobalContentElementView extends BaseGlobalContentElementView
{
    use IconForType;

    public function toArray($request)
    {
        $this->resource->load('mediaUses.media');
        $this->resource->load('contentElement.fields.childElement.fields.childElement.fields.childElement.fields');
        $this->resource->setVisible([
            'id',
            'fields',
            'slug',
            'name',
            'ui_component',
            'element_id',
            'available_from',
            'available_to',
            'content',
            'type',
            'preview_image',
        ]);
        if (!empty($this->resource->preview_image)) {
            $this->resource['preview_image'] = [
                'url' => Storage::disk(Config::get('filesystems.default_media'))->url($this->resource->preview_image),
                'path' => $this->resource->preview_image,
            ];
        }
        $data = $this->resource->toArray();
        $data['content'] = [
            [
                'id' => $this->resource->id,
                'element_id' => $this->resource->element_id,
                'slug' => $this->resource->contentElement?->slug,
                'name' => $this->resource->contentElement?->title,
                'repeatable' => $this->resource->contentElement?->data['repeatable'] ?? false,
                'optionsMenuVisible' => false,
                'nestable' => $this->resource->contentElement?->data['nestable'] ?? false,
                'nestedLimit' => $this->resource->contentElement?->data['nested_limit'] ?? null,
                'icon' => $this->resource->contentElement?->icon,
                'component' => 'EditableContent' . $this->getComponent('group'),
                'componentName' => $this->getComponent('group'),
                'content' => '',
                'children' => $this->childElementContentMap(
                    $this->resource->contentElement,
                    $this->resource->content[0]['children'] ?? []
                )
            ]
        ];
        $data['elements'] = $this->getElementList();
        $data['created_at'] = $this->resource->created_at?->format('d/m/Y H:i');
        $data['updated_at'] = $this->resource->updated_at?->format('d/m/Y H:i');
        return $data;
    }

    protected function mapField($field, $content)
    {
        $data = $this->getMatchedContent($field, $content);
        $field->setHidden([
            'element_id',
            'child_element_id',
            'created_at',
            'updated_at',
        ]);
        $field->id = random_int(1, 99999);
        $field->editable = true;
        $field->optionsMenuVisible = false;
        $field->content = $data['content'] ?? null;
        $field->nestedLimit = $field->data['nestedLimit'] ?? false;
        $field->nestable = $field->data['nestable'] ?? false;
        $field->repeatable = $field->data['repeatable'] ?? false;
        $field->meta = $this->getMetaFromContent($field, $content);
        $field->icon = $this->getIcon($field->field_type);
        $field->component = 'EditableContent' . $this->getComponent($field->field_type);
        $field->componentName = $this->getComponent($field->field_type);
        $field->children = $field->child_element_id
            ? $this->childElementContentMap(
                $field->childElement,
                $data['children'] ?? null
            )
            : [];

        $field->makeHidden('childElement');
        return $field;
    }

    private function getMetaFromContent($field, $content)
    {
        $meta = $field->meta ?? [];
        if ($field->field_type === 'image') {
            $meta['selected'] = $this->resource->mediaUses
                ->filter(fn(MediaUse $mediaUse) => in_array($mediaUse->media_id, $field->content ?? []))
                ->map(fn(MediaUse $mediaUse) => new MediaEntryResource($mediaUse))
                ->values();
        }

        return $meta;
    }

    protected function getComponent(string $type): string
    {
        return match ($type) {
            'text' => 'TextField',
            'image' => 'ImageUpload',
            'boolean', 'confirm' => 'Boolean',
            'editor' => 'Editor',
            'checkbox', 'checkbox-list' => 'CheckboxList',
            'coords', 'location' => 'LocationPicker',
            'number' => 'NumberField',
            'select' => 'SelectField',
            'date', 'datetime' => 'DateTimeField',
            'group', 'element' => 'Group',
            'form-field' => 'FormField',
            default => '',
        };
    }

    private function getElementList()
    {
        return ContentElement::query()
            ->select(['id', 'title as name'])
            ->orderBy('name')
            ->active()
            ->get();
    }

    protected function getAttributeFormContent($field, $fromContent, string $attribute = 'content')
    {
        if (isset($fromContent['slug'])) {
            $value = $fromContent;
        } else {
            $value = collect($fromContent)
                ->filter(fn($value) => ($value['slug'] ?? '') === $field->slug)
                ->first();
        }

        return $value[$attribute] ?? null;
    }

    protected function getMatchedContent($field, $fromContent)
    {
        // Has slug, is already object and not a list
        if (isset($fromContent['slug'])) {
            return $fromContent;
        }

        $value = collect($fromContent)->filter(fn($value) => ($value['slug'] ?? '') === $field->slug);
        if ($value->count() == 1) {
            return $value->first();
        }

        $value = $value->filter(fn($value) => ($value['name'] ?? '') === $field->name);
        return $value->first() ?? null;
    }

    private function isContentRepeated($resource, $content): bool
    {
        $unique_elements = collect($content)
            ->map(fn($entry) => $entry['slug'] ?? null)
            ->unique()
            ->count();

        return $resource?->fields->count() == 1
            && $unique_elements === 1;
    }

    private function repeaterContentMap(ContentElementField $field, ?array $repeated_content): Collection
    {
        return collect($repeated_content)
            ->map(fn($content) => $this->mapField(new ContentElementField($field->toArray()), $content))
            ->values();
    }

    protected function childElementContentMap($resource, $content): ?Collection
    {
        if ($this->isContentRepeated($resource, $content)) {
            return $this->repeaterContentMap($resource->fields->first(), $content);
        }

        return $resource?->fields
            ->map(fn($field) => $this->mapField($field, $content))
            ->values();
    }
}
