<?php

namespace App\Domains\Tenant\Resources;

use App\Domains\Attachable\Models\Attachment;
use App\Domains\Attachable\Models\AttachmentCrop;
use App\Domains\Catalog\Models\Category;
use App\Domains\Menu\Models\Menu;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

/**
 * @mixin Tenant
 */
class TenantResource extends JsonResource
{
    /**
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'client_id' => $this->client_id,
            'codigo' => $this->codigo,
            'nombre' => $this->nombre,
            'dominio' => $this->dominio,
            'base_path' => $this->base_path,
            'site_title' => $this->site_title
                ?? $this->websiteType?->site_title
                ?? 'ShopitFront',
            'address' => $this->address,
            'phone' => $this->phone,
            'favicon' => ($this->favicon ?? $this->websiteType?->favicon)
                ?->getTemporaryUrl(1440),
            'primary_color' => $this->primary_color,
            'secondary_color' => $this->secondary_color,
            'danger_color' => $this->danger_color,
            'success_color' => $this->success_color,
            'header_bg_color' => $this->header_bg_color,
            'footer_bg_color' => $this->footer_bg_color,
            'website_type_code' => $this->website_type_code,
            'event_date_text' => $this->event_date_text,
            'event' => $this->whenLoaded('eventDates', fn () => $this->event_title === null
                ? null
                : [
                    'title' => $this->event_title,
                    'location' => $this->event_location,
                    'dates' => $this->eventDates->map(fn ($eventDate): array => [
                        'id' => $eventDate->id,
                        'date' => $eventDate->date->format('Y-m-d'),
                        'time_start' => $eventDate->time_start,
                        'time_end' => $eventDate->time_end,
                    ])->values(),
                ]),
            'extras' => $this->whenLoaded(
                'websiteExtras',
                fn () => $this->websiteExtras
                    ->filter(fn ($extra) => $extra->is_enabled)
                    ->mapWithKeys(fn ($extra) => [
                        $extra->websiteTypeExtra->codigo => $this->formatExtraConfig(
                            $extra->resolvedConfig()
                        ),
                    ])
            ),
            // 1 day
            'header_logo' => $this->headerLogo?->getTemporaryUrl(1440),
            'footer_logo' => $this->footerLogo?->getTemporaryUrl(1440),
            'header_bg_image' => $this->headerBackgroundImage?->getTemporaryUrl(1440),
            'footer_bg_image' => $this->footerBackgroundImage?->getTemporaryUrl(1440),
            'search_product_layout' => $this->search_product_layout->value,
            'search_group_layout' => $this->search_group_layout->value,
            'search_items_per_page' => $this->search_items_per_page,
            'display_categories' => $this->display_categories,
            'display_seach_bar' => $this->display_seach_bar,
            'display_cart' => $this->display_cart,
            'cart_editing_policy' => CartEditingPolicyResource::make($this->cart_editing_policy),
            'checkout_editing_policy' => CartEditingPolicyResource::make($this->checkout_editing_policy),
            'display_cart_item_images' => $this->display_cart_item_images,
            'scanner_category_validation_enabled' => $this->scanner_category_validation_enabled,
            'social_media' => $this->whenLoaded(
                'socialMedia',
                fn () => $this->socialMedia
                    ->map(fn ($socialMedia) => [
                        'code' => $socialMedia->code,
                        'icon' => $socialMedia->icon,
                        'name' => $socialMedia->name,
                        'url' => $socialMedia->pivot->url,
                    ])
                    ->values()
            ),
            'menues' => $this->whenLoaded(
                'menues',
                fn () => $this->menuTree($this->menues)
            ),
            'categories' => $this->whenLoaded(
                'categories',
                fn () => $this->categoryTree($this->categories)
            ),
        ];
    }

    private function formatExtraConfig(mixed $value): mixed
    {
        if ($value instanceof Attachment) {
            $crops = $value->cropVariants->keyBy('variant');
            $desktop = $crops->get(AttachmentCrop::DESKTOP)?->croppedAttachment ?? $value;
            $mobile = $crops->get(AttachmentCrop::MOBILE)?->croppedAttachment ?? $desktop;

            if ($crops->isEmpty()) {
                return $value->getTemporaryUrl(1440);
            }

            return [
                'desktop' => $desktop->getTemporaryUrl(1440),
                'mobile' => $mobile->getTemporaryUrl(1440),
            ];
        }

        if (! is_array($value)) {
            return $value;
        }

        foreach ($value as $key => $item) {
            $value[$key] = $this->formatExtraConfig($item);
        }

        return $value;
    }

    /**
     * @param  Collection<int, Category>  $categories
     * @return Collection<int, array<string, mixed>>
     */
    private function categoryTree(Collection $categories): Collection
    {
        $categoryIds = $categories->pluck('id')->flip();
        $childrenByParent = $categories
            ->filter(fn (Category $category) => $category->categoria_id !== null
                && $categoryIds->has($category->categoria_id))
            ->groupBy('categoria_id');

        $formatCategory = function (Category $category) use (&$formatCategory, $childrenByParent): array {
            return [
                'id' => $category->id,
                'nombre' => $category->nombre,
                'subcategories' => $childrenByParent
                    ->get($category->id, collect())
                    ->map($formatCategory)
                    ->values(),
            ];
        };

        return $categories
            ->filter(fn (Category $category) => $category->categoria_id === null
                || ! $categoryIds->has($category->categoria_id))
            ->map($formatCategory)
            ->values();
    }

    /**
     * @param  Collection<int, Menu>  $menus
     * @return Collection<int, array<string, mixed>>
     */
    private function menuTree(Collection $menus): Collection
    {
        $menuCodes = $menus->pluck('code')->flip();
        $childrenByParent = $menus
            ->filter(fn (Menu $menu) => $menu->parent_menu_code !== null)
            ->groupBy('parent_menu_code');

        $formatMenu = function (Menu $menu) use (&$formatMenu, $childrenByParent): array {
            $formatted = [
                'id' => $menu->id,
                'code' => $menu->code,
                'label' => $menu->label,
                'parent_menu_code' => $menu->parent_menu_code,
                'content_type' => $menu->content_type,
                'route' => $menu->route,
            ];

            if ($menu->pivot?->static_content !== null) {
                $formatted['static_content'] = $menu->pivot->static_content;
            }

            $formatted['submenues'] = $childrenByParent
                ->get($menu->code, collect())
                ->sortBy(
                    fn (Menu $submenu) => Str::lower(Str::ascii($submenu->label)),
                    SORT_NATURAL
                )
                ->map($formatMenu)
                ->values();

            return $formatted;
        };

        return $menus
            ->filter(fn (Menu $menu) => $menu->parent_menu_code === null
                || ! $menuCodes->has($menu->parent_menu_code))
            ->sortBy(
                fn (Menu $menu) => Str::lower(Str::ascii($menu->label)),
                SORT_NATURAL
            )
            ->map($formatMenu)
            ->values();
    }
}
