<?php

namespace App\Http\Resources;

use App\Facades\Settings;
use App\Facades\Site;
use App\Traits\IconForType;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Mtc\ContentManager\Contracts\MediaUse;
use Mtc\ContentManager\Http\Resources\MediaEntryResource;
use Mtc\ContentManager\Models\ContentElementField;
use Mtc\MercuryDataModels\CarConfiguratorExtra;
use Mtc\MercuryDataModels\CarConfiguratorModel;
use Mtc\MercuryDataModels\CarConfiguratorPackage;
use Mtc\MercuryDataModels\ContentElement;
use Mtc\MercuryDataModels\DrivetrainType;
use Mtc\MercuryDataModels\FuelType;
use Mtc\MercuryDataModels\TransmissionType;
use Mtc\MercuryDataModels\VehicleMake;
use Mtc\MercuryDataModels\VehicleModel;

class CarConfiguratorView extends JsonResource
{
    use IconForType;
    use SeoDataForModel;

    public static $wrap = '';

    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    #[\Override]
    public function toArray(Request $request): array
    {
        $this->resource->load([
            'make',
            'model',
            'sections',
            'trims.restrictions',
            'engines.restrictions',
            'colours.restrictions',
            'wheels.restrictions',
            'interiors.restrictions',
            'packages.restrictions',
            'extras.restrictions',
            'custom.restrictions',
            'editions.mediaUses.media',
            'trims.mediaUses.media',
            'engines.mediaUses.media',
            'colours.mediaUses.media',
            'wheels.mediaUses.media',
            'interiors.mediaUses.media',
            'packages.mediaUses.media',
            'extras.mediaUses.media',
            'custom.mediaUses.media',
        ]);

        $this->resource->sections = $this->resource->sections
            ->each(function ($section) {
                $section->edit = false;
                $section->object_type = $section->custom ? 'Custom' : Str::singular($section->name);
                $section->data ??= ['interior' => false, 'exterior' => false];
            });
        $resource = $this->resource->toArray();
        $resource['seo'] = $this->getSeoData($this->resource);
        $resource['site_url'] = Site::configuratorUrl($this->resource);

        $element = ContentElement::query()->find(Settings::get('configurator-content-element'));
        if ($element) {
            $resource['content'] = [
                [
                    'id' => $this->resource->id,
                    'element_id' => $element->id,
                    'slug' => $element->slug,
                    'name' => $element->title,
                    'repeatable' => $element->data['repeatable'] ?? false,
                    'optionsMenuVisible' => false,
                    'nestable' => $element->data['nestable'] ?? false,
                    'nestedLimit' => $element->data['nested_limit'] ?? null,
                    'icon' => $element->icon,
                    'component' => 'EditableContent' . $this->getComponent('group'),
                    'componentName' => $this->getComponent('group'),
                    'content' => '',
                    'children' => $this->childElementContentMap(
                        $element,
                        $this->resource->data[0]['children'] ?? []
                    )
                ]
            ];
        } else {
            $resource['content'] = [];
        }
        $existing_restrictions = $this->resource->restrictions()
            ->whereIn('functionality_type', ['packages', 'extras'])
            ->get()
            ->groupBy('functionality_type')
            ->map(fn ($group) => $group->groupBy('functionality_id'));
        foreach (CarConfiguratorModel::$relationship_models as $relationship) {
            $resource[$relationship] = $this->resource[$relationship]
                ->map(function ($related) use ($relationship, $existing_restrictions) {
                    if (in_array($relationship, ['packages', 'extras'])) {
                        return array_merge(
                            $related->pivot->toArray(),
                            ['restrictions' => $existing_restrictions[$relationship][$related->id] ?? []]
                        );
                    }
                    $data = $related->toArray();
                    $data['media'] = $related->mediaUses->pluck('media_id');
                    $data['media_uses'] = $related->mediaUses
                        ->map(fn (MediaUse $mediaUse) => new MediaEntryResource($mediaUse));
                    return $data;
                });
        }

        return [
            'configurator' => $resource,
            'makes' => VehicleMake::query()->with('filterIndex')->select(['id', 'name'])->get(),
            'models' => VehicleModel::query()
                ->with('filterIndex')
                ->where('make_id', $this->resource->make_id)
                ->select(['id', 'name'])
                ->get(),
            'packages' => CarConfiguratorPackage::query()->get()
                ->groupBy(fn ($entry) => $entry->category ?? __('labels.no_category')),
            'extras' => CarConfiguratorExtra::query()->get()
                ->groupBy(fn ($entry) => $entry->category ?? __('labels.no_category')),
            'drivetrains' => DrivetrainType::query()->with('filterIndex')->select(['id', 'name'])->get(),
            'transmissions' => TransmissionType::query()->with('filterIndex')->select(['id', 'name'])->get(),
            'fuel_types' => FuelType::query()
                ->with('filterIndex')
                ->select(['id', 'name', 'mpg_data', 'ev_data'])
                ->get(),

        ];
    }

    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 => '',
        };
    }

    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();
    }
}
