<?php

namespace App\Services;

use App\Models\ShopDepartment;
use App\Models\ShopProduct;
use App\Models\ShopProductVariant;
use App\Models\ShopSection;
use App\Models\ShopSetting;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

class ShopCatalogService
{
    public function bootstrap(bool $admin = false): array
    {
        $products = $this->withSalesMetrics(ShopProduct::query())
            ->with(['category', 'images', 'variants', 'reviews' => fn ($query) => $query
                ->where('status', 'approved')
                ->latest('published_at')])
            ->when(! $admin, fn (Builder $query) => $query->where('is_active', true))
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();

        $departments = ShopDepartment::query()
            ->with(['branches' => fn ($query) => $query
                ->when(! $admin, fn ($branchQuery) => $branchQuery->where('is_active', true))
                ->with(['items' => fn ($itemQuery) => $itemQuery
                    ->when(! $admin, fn ($activeQuery) => $activeQuery->where('is_active', true))
                    ->with('products:id')])])
            ->when(! $admin, fn (Builder $query) => $query->where('is_active', true))
            ->orderBy('sort_order')
            ->get();

        $serializedProducts = $products->map(
            fn (ShopProduct $product) => $this->product($product, $admin)
        );

        return [
            'settings' => $this->settings($admin),
            'sections' => ShopSection::query()
                ->when(! $admin, fn (Builder $query) => $query->where('is_visible', true))
                ->orderBy('sort_order')
                ->get()
                ->map(fn (ShopSection $section) => $this->section($section))
                ->values(),
            'departments' => $departments
                ->map(fn (ShopDepartment $department) => $this->department($department))
                ->values(),
            'productsByCategory' => $serializedProducts
                ->filter(fn (array $product) => ($product['source'] ?? 'category') !== 'catalog')
                ->groupBy(fn (array $product) => $product['categorySlug'] ?: 'uncategorized')
                ->map(fn (Collection $group) => $group->values())
                ->all(),
            'catalogProducts' => $serializedProducts
                ->filter(fn (array $product) => ($product['source'] ?? '') === 'catalog')
                ->values(),
            'products' => $serializedProducts->values(),
        ];
    }

    public function settings(bool $admin = false): array
    {
        return ShopSetting::query()
            ->when(! $admin, fn (Builder $query) => $query->where('is_public', true))
            ->orderBy('key')
            ->get()
            ->mapWithKeys(fn (ShopSetting $setting) => [
                $setting->key => $this->castSetting($setting->value, $setting->type),
            ])
            ->all();
    }

    public function findProduct(string|int $identifier): ?ShopProduct
    {
        $with = ['category', 'images', 'variants', 'catalogItems.branch.department', 'reviews' => fn ($query) => $query
            ->where('status', 'approved')
            ->latest('published_at')];

        $product = $this->withSalesMetrics(ShopProduct::query())
            ->with($with)
            ->where('is_active', true)
            ->where(function (Builder $query) use ($identifier): void {
                $query->where('slug', (string) $identifier);
                if (is_numeric($identifier)) {
                    $query->orWhere('id', (int) $identifier);
                }
            })
            ->first();

        if ($product || ! is_numeric($identifier)) {
            return $product;
        }

        $variant = ShopProductVariant::query()
            ->where('external_id', (int) $identifier)
            ->where('is_active', true)
            ->first();

        if (! $variant) {
            return null;
        }

        return $this->withSalesMetrics(ShopProduct::query())
            ->with($with)
            ->whereKey($variant->product_id)
            ->where('is_active', true)
            ->first();
    }

    public function product(ShopProduct $product, bool $admin = false): array
    {
        $product->loadMissing(['category', 'images', 'variants', 'reviews']);
        $metadata = $product->metadata ?: [];
        $images = $product->images->pluck('url')->filter()->values()->all();
        $inStock = ! $product->track_inventory || $product->stock_quantity > 0;

        return [
            'id' => $product->id,
            'slug' => $product->slug,
            'sku' => $product->sku,
            'name' => $product->name,
            'category' => $product->category_label ?: $product->category?->name,
            'categoryId' => $product->category_id,
            'categorySlug' => $product->category?->slug,
            'description' => $product->description ?: $product->short_description,
            'shortDescription' => $product->short_description,
            'image' => $product->image ?: ($images[0] ?? null),
            'images' => $images,
            'basePrice' => (float) $product->price,
            'price' => (float) $product->price,
            'compareAtPrice' => $product->compare_at_price !== null
                ? (float) $product->compare_at_price
                : null,
            'isOnSale' => $product->compare_at_price !== null
                && (float) $product->compare_at_price > (float) $product->price,
            'rating' => (float) $product->rating,
            'reviewCount' => $product->review_count,
            'purchasedLast30Days' => (int) ($product->purchased_last_30_days ?? 0),
            'inStock' => $inStock,
            'stockCount' => $product->stock_quantity,
            'isFeatured' => $product->is_featured,
            'isActive' => $product->is_active,
            'productType' => $product->product_type,
            'brand' => $product->brand,
            'baseFeatures' => $product->base_features ?: [],
            'specs' => $product->specifications ?: [],
            'upgradeOptions' => $product->upgrade_options ?: new \stdClass,
            'source' => $metadata['source'] ?? 'category',
            'variants' => $product->variants
                ->filter(fn (ShopProductVariant $variant) => $admin || $variant->is_active)
                ->map(fn (ShopProductVariant $variant) => [
                    'id' => $variant->external_id ?: $variant->id,
                    'variantId' => $variant->id,
                    'name' => $variant->name,
                    'label' => $variant->label,
                    'sku' => $variant->sku,
                    'price' => (float) $variant->price,
                    'compareAtPrice' => $variant->compare_at_price !== null
                        ? (float) $variant->compare_at_price
                        : null,
                    'rating' => (float) $variant->rating,
                    'image' => $variant->image ?: $product->image,
                    'images' => $variant->images ?: [],
                    'features' => $variant->features ?: [],
                    'attributes' => $variant->attributes ?: new \stdClass,
                    'stockCount' => $variant->stock_quantity,
                    'inStock' => $variant->stock_quantity > 0,
                    'isActive' => $variant->is_active,
                ])->values(),
            'reviews' => $product->reviews
                ->map(fn ($review) => [
                    'id' => $review->id,
                    'user' => $review->customer_name,
                    'name' => $review->customer_name,
                    'title' => $review->title,
                    'comment' => $review->body,
                    'rating' => $review->rating,
                    'verified' => $review->is_verified,
                    'date' => optional($review->published_at ?: $review->created_at)->toIso8601String(),
                ])->values(),
            'metadata' => $metadata,
            'catalogItemIds' => $product->relationLoaded('catalogItems')
                ? $product->catalogItems->pluck('id')->values()
                : [],
        ];
    }

    private function department(ShopDepartment $department): array
    {
        return [
            'id' => $department->id,
            'name' => $department->name,
            'shortName' => $department->short_name,
            'slug' => $department->slug,
            'kicker' => $department->kicker,
            'description' => $department->description,
            'heroImage' => $department->hero_image,
            'heroBackgroundImage' => $department->hero_background_image,
            'heroContent' => $department->hero_content ?: new \stdClass,
            'heroStyles' => $department->hero_styles ?: new \stdClass,
            'sortOrder' => $department->sort_order,
            'isActive' => $department->is_active,
            'branches' => $department->branches->map(fn ($branch) => [
                'id' => $branch->id,
                'title' => $branch->title,
                'slug' => $branch->slug,
                'label' => $branch->label,
                'description' => $branch->description,
                'image' => $branch->image,
                'sortOrder' => $branch->sort_order,
                'isActive' => $branch->is_active,
                'items' => $branch->items->map(fn ($item) => [
                    'id' => $item->id,
                    'title' => $item->title,
                    'slug' => $item->slug,
                    'kind' => $item->kind,
                    'description' => $item->description,
                    'image' => $item->image,
                    'features' => $item->features ?: [],
                    'productIds' => $item->products->pluck('id')->values(),
                    'sortOrder' => $item->sort_order,
                    'isActive' => $item->is_active,
                ])->values(),
            ])->values(),
        ];
    }

    private function section(ShopSection $section): array
    {
        return [
            'id' => $section->id,
            'key' => $section->key,
            'type' => $section->type,
            'name' => $section->name,
            'heading' => $section->heading,
            'subheading' => $section->subheading,
            'content' => $section->content ?: new \stdClass,
            'styles' => $section->styles ?: new \stdClass,
            'sortOrder' => $section->sort_order,
            'isVisible' => $section->is_visible,
        ];
    }

    private function castSetting(?string $value, string $type): mixed
    {
        return match ($type) {
            'boolean' => filter_var($value, FILTER_VALIDATE_BOOLEAN),
            'integer' => (int) $value,
            'decimal' => (float) $value,
            'json' => json_decode($value ?: 'null', true),
            default => $value,
        };
    }

    public function withSalesMetrics(Builder $query): Builder
    {
        return $query->withSum([
            'orderItems as purchased_last_30_days' => fn (Builder $itemQuery) => $itemQuery
                ->where('shop_order_items.created_at', '>=', now()->subDays(30))
                ->whereHas('order', fn (Builder $orderQuery) => $orderQuery
                    ->where('status', '!=', 'cancelled')
                    ->whereNotIn('payment_status', ['failed', 'refunded'])),
        ], 'quantity');
    }
}
