<?php

namespace Daylight\Core\Modules\PageBuilder\Transformers;

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

class ComponentDataTransformer
{
    public static function for(Collection $components): Collection
    {
        $registry = app(ComponentRegistry::class);

        return $components->map(function (Component $component) use ($registry) {
            return [
                'id' => $component->id,
                'type' => $component->type,
                'data' => [
                    ...$component->data,
                    ...self::getRepeaterMediaFields($registry, $component),
                    ...self::getMediaFields($registry, $component),
                    ...self::getRelatableFields($registry, $component),
                ],
            ];
        });
    }

    private static function getRelatableFields(ComponentRegistry $registry, Component $component): array
    {
        return $registry->getDefinition($component->type)
            ->fields()
            ->filter(fn ($f) => $f->type === 'related')
            ->mapWithKeys(function ($field) use ($component) {
                $relatables = $component->relatables()
                    ->where('relatable_type', $field->relatedType)
                    ->orderBy('order')
                    ->get();

                // Get the IDs in the correct order
                $orderedIds = $relatables->pluck('relatable_id')->toArray();

                // Fetch the full related model data
                if (empty($orderedIds)) {
                    return [$field->name => []];
                }

                $modelClass = $field->relatedType;

                if (! class_exists($modelClass) || ! method_exists($modelClass, 'getForRelation')) {
                    return [$field->name => []];
                }

                // Fetch full data and preserve the order from relatables table
                $relatedItems = $modelClass::getForRelation($orderedIds);

                // Re-order the items based on the original order from relatables
                $orderedItems = collect($orderedIds)->map(function ($id) use ($relatedItems) {
                    return $relatedItems->firstWhere('id', $id);
                })->filter()->values()->toArray();

                return [
                    $field->name => $orderedItems,
                ];
            })
            ->all();
    }

    private static function getMediaFields(ComponentRegistry $registry, Component $component): array
    {
        return $registry->getDefinition($component->type)
            ->fields()
            ->filter(fn ($f) => $f->type === 'media')
            ->mapWithKeys(function ($field) use ($component) {
                return [
                    $field->name => self::getComponentMediaByField($component, $field->name),
                ];
            })
            ->all();
    }

    private static function getRepeaterMediaFields(ComponentRegistry $registry, Component $component): array
    {
        return $registry->getDefinition($component->type)
            ->fields()
            ->filter(fn ($f) => $f->type === 'repeater')
            ->mapWithKeys(function ($field) use ($component) {
                $mediaFields = collect($field->items)->filter(fn ($f) => $f->type === 'media');

                $data = collect($component->data[$field->name] ?? [])
                    ->map(function (array $row, $index) use ($component, $field, $mediaFields) {
                        foreach ($mediaFields as $mediaField) {
                            $pivotField = "{$field->name}.{$index}.{$mediaField->name}";
                            $row[$mediaField->name] = self::getComponentMediaByField($component, $pivotField);
                        }

                        return $row;
                    });

                return [$field->name => $data->toArray()];
            })
            ->all();
    }

    private static function getComponentMediaByField(Component $component, string $fieldName): array
    {
        return $component->media
            ->where('pivot.properties.field', $fieldName)
            ->map(fn ($media) => self::formatMedia($media))
            ->values()
            ->toArray();
    }

    private static function formatMedia($media): array
    {
        return [
            'id' => $media->id,
            'name' => $media->name,
            'handle' => $media->handle,
            'size' => $media->size,
            'type' => $media->type,
            'url' => $media->getUrl('thumbnail'),
        ];
    }
}
