<?php

namespace App\Http\Controllers\Frontend;

use App\Http\Controllers\Controller;
use App\Models\Brand;
use App\Models\Category;
use App\Models\Color;
use App\Models\Product;
use App\Models\Size;
use Illuminate\Contracts\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Http\Request;
use Illuminate\View\View;

class ShopController extends Controller
{
    public function index(Request $request): View
    {
        return $this->render($request, fn (EloquentBuilder $q) => $q, 'Shop All');
    }

    public function newArrivals(Request $request): View
    {
        return $this->render($request, fn (EloquentBuilder $q) => $q->newArrival(), 'New Arrivals');
    }

    public function sale(Request $request): View
    {
        return $this->render($request, fn (EloquentBuilder $q) => $q->whereNotNull('sale_price'), 'Sale');
    }

    private function render(Request $request, \Closure $scope, string $title): View
    {
        $query = $scope(Product::active()->withRatings()->with(['primaryImage', 'category', 'brand']));

        if ($request->filled('search')) {
            $query->search($request->string('search'));
        }
        if ($request->filled('category')) {
            $query->whereHas('category', fn ($q) => $q->where('slug', $request->string('category')));
        }
        if ($request->filled('brand')) {
            $query->whereHas('brand', fn ($q) => $q->where('slug', $request->string('brand')));
        }
        if ($request->filled('color')) {
            $query->whereHas('variants', fn ($q) => $q->where('color_id', $request->integer('color')));
        }
        if ($request->filled('size')) {
            $query->whereHas('variants', fn ($q) => $q->where('size_id', $request->integer('size')));
        }
        if ($request->filled('min_price')) {
            // CAST is required for correctness on SQLite: COALESCE() can
            // drop column type affinity, silently falling back to a string
            // comparison where any numeric literal sorts below any decimal
            // stored as text. MySQL happens to compare these correctly
            // without it, but the cast keeps behavior identical everywhere.
            $query->whereRaw('CAST(COALESCE(sale_price, original_price) AS DECIMAL(10,2)) >= ?', [$request->float('min_price')]);
        }
        if ($request->filled('max_price')) {
            $query->whereRaw('CAST(COALESCE(sale_price, original_price) AS DECIMAL(10,2)) <= ?', [$request->float('max_price')]);
        }
        if ($request->boolean('featured')) {
            $query->featured();
        }
        if ($request->boolean('trending')) {
            $query->trending();
        }

        match ($request->string('sort')->toString()) {
            'price_asc' => $query->orderByRaw('CAST(COALESCE(sale_price, original_price) AS DECIMAL(10,2)) asc'),
            'price_desc' => $query->orderByRaw('CAST(COALESCE(sale_price, original_price) AS DECIMAL(10,2)) desc'),
            'oldest' => $query->oldest(),
            default => $query->latest(),
        };

        $products = $query->paginate(12)->withQueryString();

        return view('frontend.shop.index', [
            'products' => $products,
            'title' => $title,
            'categories' => Category::active()->root()->orderBy('name')->get(),
            'brands' => Brand::active()->orderBy('name')->get(),
            'colors' => Color::orderBy('name')->get(),
            'sizes' => Size::orderBy('sort_order')->get(),
        ]);
    }
}
