<?php

namespace App\Services;

use App\Models\Product;
use App\Models\UserProductInteraction;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;

class ProductRecommendationService
{
    public function getPersonalizedRecommendations(?int $userId, int $limit = 5): Collection
    {
        if (! $userId) {
            return $this->getTrendingProducts($limit);
        }

        $interactedProducts = UserProductInteraction::forUser($userId)
            ->select('product_id', DB::raw('SUM(count) as total_interactions'))
            ->groupBy('product_id')
            ->orderBy('total_interactions', 'desc')
            ->pluck('product_id');

        if ($interactedProducts->isEmpty()) {
            return $this->getTrendingProducts($limit);
        }

        $categories = Product::whereIn('id', $interactedProducts)
            ->select('category_id')
            ->distinct()
            ->pluck('category_id');

        return Product::query()
            ->whereIn('category_id', $categories)
            ->whereNotIn('id', $interactedProducts)
            ->with('category')
            ->orderBy('positive_feedback', 'desc')
            ->orderBy('sales_180day', 'desc')
            ->limit($limit)
            ->get();
    }

    public function getRecommendationsByCategory(
        int $categoryId,
        ?string $criteria = null,
        int $limit = 10
    ): Collection {
        $query = Product::query()
            ->where('category_id', $categoryId)
            ->with('category');

        $query = match ($criteria) {
            'best_selling' => $query->orderBy('sales_180day', 'desc'),
            'top_rated' => $query->orderBy('positive_feedback', 'desc'),
            'price_low' => $query->orderBy('price', 'asc'),
            'price_high' => $query->orderBy('price', 'desc'),
            'most_viewed' => $query->orderBy('clicks', 'desc'),
            default => $query->orderBy('sales_180day', 'desc'),
        };

        return $query->limit($limit)->get();
    }

    public function getTrendingProducts(int $limit = 10): Collection
    {
        return Product::query()
            ->with('category')
            ->orderBy('sales_180day', 'desc')
            ->orderBy('clicks', 'desc')
            ->limit($limit)
            ->get();
    }

    public function getSimilarProducts(int $productId, int $limit = 5): Collection
    {
        $product = Product::with('category')->findOrFail($productId);

        return Product::query()
            ->where('category_id', $product->category_id)
            ->where('id', '!=', $productId)
            ->with('category')
            ->orderBy('positive_feedback', 'desc')
            ->limit($limit)
            ->get();
    }

    public function getRecommendationsByPriceRange(
        float $minPrice,
        float $maxPrice,
        ?int $categoryId = null,
        int $limit = 10
    ): Collection {
        return Product::query()
            ->when($categoryId, fn ($q) => $q->where('category_id', $categoryId))
            ->whereBetween('price', [$minPrice, $maxPrice])
            ->with('category')
            ->orderBy('positive_feedback', 'desc')
            ->orderByDiscount('desc')
            ->limit($limit)
            ->get();
    }

    public function getDealsOfTheDay(int $limit = 10): Collection
    {
        return Product::query()
            ->whereHasDiscount()
            ->with('category')
            ->orderByDiscount('desc')
            ->limit($limit)
            ->get();
    }
}
