<?php

namespace App\Repositories;

use App\Models\Category;
use App\Models\Product;
use App\ProductRepositoryInterface;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;

class ProductRepository implements ProductRepositoryInterface
{
    public function find(int $id): ?Product
    {
        return Product::find($id);
    }

    public function findBySlug(string $slug): ?Product
    {
        return Product::where('slug', $slug)->first();
    }

    public function findActive(int $id): ?Product
    {
        return Product::active()->forWebsite()->find($id);
    }

    public function findActiveBySlug(string $slug): ?Product
    {
        return Product::active()
            ->forWebsite()
            ->where('slug', $slug)
            ->with(['category', 'unit', 'media'])
            ->first();
    }

    public function getActive(): Collection
    {
        return Product::active()->forWebsite()->get();
    }

    public function getFeatured(int $limit = 8): Collection
    {
        return Product::with(['category', 'unit', 'variants' => function($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products in listings
            ->active()
            ->forWebsite()
            ->featured()
            ->inStock()
            ->latest()
            ->take($limit)
            ->get();
    }

    public function getInStock(int $limit = null): Collection
    {
        $query = Product::whereNull('parent_id') // Only parent products
            ->active()
            ->forWebsite()
            ->inStock();
        
        if ($limit) {
            $query->take($limit);
        }
        
        return $query->get();
    }

    public function getNewArrivals(int $limit = 8): Collection
    {
        return Product::with(['category', 'unit', 'variants' => function($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products
            ->active()
            ->forWebsite()
            ->inStock()
            ->latest()
            ->take($limit)
            ->get();
    }

    public function getOnSale(int $limit = 8): Collection
    {
        return Product::with(['category', 'unit', 'variants' => function($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products
            ->active()
            ->forWebsite()
            ->inStock()
            ->whereColumn('mrp', '>', 'price')
            ->whereNotNull('mrp')
            ->latest()
            ->take($limit)
            ->get();
    }

    public function getByCategory(int $categoryId, array $options = []): LengthAwarePaginator
    {
        $query = Product::with(['category', 'unit', 'variants' => function($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products
            ->where('category_id', $categoryId)
            ->active()
            ->forWebsite();

        if ($options['in_stock'] ?? true) {
            $query->inStock();
        }

        if (isset($options['featured'])) {
            $query->featured();
        }

        $perPage = $options['per_page'] ?? 20;

        return $query->latest()->paginate($perPage);
    }

    public function getByCategories(array $categoryIds, array $options = []): LengthAwarePaginator
    {
        $query = Product::with(['category', 'unit', 'variants' => function ($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products
            ->whereIn('category_id', $categoryIds)
            ->active()
            ->forWebsite();

        if ($options['in_stock'] ?? true) {
            $query->inStock();
        }

        if (isset($options['featured'])) {
            $query->featured();
        }
        
        $perPage = $options['per_page'] ?? 10;

        return $query->latest()->paginate($perPage);
    }

    public function search(string $query, array $filters = []): LengthAwarePaginator
    {
        $productQuery = Product::with(['category', 'unit', 'variants' => function($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->whereNull('parent_id') // Only parent products
            ->active()
            ->forWebsite();

        // Apply search query
        if (!empty($query)) {
            $productQuery->where(function ($q) use ($query) {
                $q->where('name', 'LIKE', '%' . $query . '%')
                  ->orWhere('tags', 'LIKE', '%' . $query . '%');
            });
        }

        // Apply category filter
        if (!empty($filters['category_ids'])) {
            $productQuery->whereIn('category_id', $filters['category_ids']);
        }

        // Apply stock filter (for search we always include out-of-stock, but can keep this for other callers)
        if (array_key_exists('in_stock', $filters) && $filters['in_stock']) {
            $productQuery->inStock();
        }

        $perPage = $filters['per_page'] ?? 20;

        return $productQuery
            ->orderByRaw('CASE WHEN products.current_stock > 0 THEN 0 ELSE 1 END')
            ->latest()
            ->paginate($perPage);
    }

    public function getRelated(int $productId, int $categoryId, int $limit = 4): Collection
    {
        $baseQuery = function () {
            return Product::whereNull('parent_id')
                ->with(['category', 'variants' => function ($query) {
                    $query->where('is_active', true)->forWebsite();
                }])
                ->active()
                ->forWebsite()
                ->inStock()
                ->latest();
        };

        $fromSameCategory = $baseQuery()
            ->where('category_id', $categoryId)
            ->where('id', '!=', $productId)
            ->take($limit)
            ->get();

        if ($fromSameCategory->count() >= $limit) {
            return $fromSameCategory;
        }

        $excludeIds = $fromSameCategory->pluck('id')->push($productId)->all();
        $need = $limit - $fromSameCategory->count();
        $category = Category::find($categoryId);

        $fallbackCategoryIds = [];
        if ($category) {
            if ($category->parent_id) {
                $fallbackCategoryIds = Category::active()
                    ->where('parent_id', $category->parent_id)
                    ->where('id', '!=', $categoryId)
                    ->pluck('id')
                    ->all();
                if (empty($fallbackCategoryIds)) {
                    $fallbackCategoryIds = [$category->parent_id];
                }
            } else {
                $fallbackCategoryIds = Category::active()
                    ->root()
                    ->where('id', '!=', $categoryId)
                    ->pluck('id')
                    ->all();
            }
        }

        if (empty($fallbackCategoryIds)) {
            return $fromSameCategory;
        }

        $additional = $baseQuery()
            ->whereIn('category_id', $fallbackCategoryIds)
            ->whereNotIn('id', $excludeIds)
            ->take($need)
            ->get();

        return $fromSameCategory->merge($additional)->take($limit);
    }

    public function getRecent(int $excludeProductId, int $limit = 4): Collection
    {
        return Product::whereNull('parent_id')
            ->where('id', '!=', $excludeProductId)
            ->with(['category', 'variants' => function ($query) {
                $query->where('is_active', true)->forWebsite();
            }])
            ->active()
            ->forWebsite()
            ->inStock()
            ->latest()
            ->take($limit)
            ->get();
    }

    public function create(array $data): Product
    {
        return Product::create($data);
    }

    public function update(Product $product, array $data): bool
    {
        return $product->update($data);
    }

    public function delete(Product $product): bool
    {
        return $product->delete();
    }
}
