<?php

namespace App\Repositories\Catalog;

use App\Models\DiscountItem;
use App\Models\Items;
use App\Models\StoreCategoryMap;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ProductRepository
{
    public function getList($params)
    {
        $event = @$params['event'];
        $sort = @$params['sort'];
        $search = @$params['search'];
        $category_id = @$params['category_id'];
        $brand_id = @$params['brand_id'];
        $gender_id = @$params['gender_id'];
        $limit = @$params['limit'];

        $location_id = @$params['location_id'];
        $is_consignment = @$params['is_consignment'];

        $price_range_start = @$params['price_range_start'];
        $price_range_end = @$params['price_range_end'];

        $sorting_ids = [];

        if ($sort == 'price_low_to_high' || $sort == 'price_high_to_low') {
            $params_filter = [];
            $params_filter['location_id'] = $location_id;
            $params_filter['sort'] = $sort;
            $sorting_ids = collect($this->getProductList($params_filter))->pluck('id')->toArray();

            // Log::info($sorting_ids);
        }

        $where_ids = [];
        if ($price_range_start && $price_range_end) {
            $params_filter = [
                'location_id' => $location_id,
                'price_range_start' => $price_range_start,
                'price_range_end' => $price_range_end,
            ];

            $where_ids = collect($this->getProductList($params_filter))
                ->pluck('id')
                ->unique()
                ->values()
                ->toArray();

            // Jika sudah ada sorting_ids → ikuti urutannya
            if (!empty($sorting_ids)) {
                $sorting_ids = array_values(array_intersect($sorting_ids, $where_ids));
            } else {
                // kalau belum ada sorting, pakai hasil filter
                $sorting_ids = $where_ids;
            }
        }



        $builder = Items::select('items.*', 'percent')
            ->leftJoin('item_dimension', 'item_dimension.no', 'items.number')
            ->leftJoin(DB::raw("(select distinct on (item_id) item_id, percent, discounts.created_at,
                case when discounts.valid_at is null then 'special-offer' else 'limited-sale' end as event
                from discount_items
                left join item_reference on item_reference_id = item_reference.id
                left join discounts on discounts.id = discount_id
                where discounts.type = 'discount' and
                ( discounts.valid_at is null or discounts.valid_at <= now()) and
                ( discounts.valid_at is null or discounts.expired_at >= now())
            order by item_id, discounts.created_at desc
                ) as d"), 'd.item_id', '=', 'items.id')
            ->when(true, function ($query) use ($event, $sort, $sorting_ids) {
                if ($event) {
                    $query->orderByRaw("case when brand = 'CHAMELO' then 1 else 2 end ASC ");

                    $query->orderBy('percent', 'desc');
                } else {

                    if (!empty($sorting_ids)) {

                        $cases = collect($sorting_ids)->map(function ($id, $index) {
                            return "WHEN items.id = {$id} THEN {$index}";
                        })->implode(' ');

                        $query->orderByRaw("
                            CASE
                                {$cases}
                                ELSE 999999
                            END
                        ");
                    } elseif ($sort == 'new') {
                        $query->orderByRaw("case when category1 in ('CLUBS','CLUB','COMPONENT HEAD') and brand = 'PXG' then 1 else 2 end ASC");
                    } else {
                        $query->orderByRaw('case when d.created_at is not null then 1 else 2 end ASC, random()');
                    }

                }

            })
            ->where('is_publish', true)
            ->when($search, function ($query) use ($search) {
                $query->where(function ($query) use ($search) {
                    $query->where('number', 'ILIKE', "%$search%")
                        ->orWhere('name', 'ILIKE', "%$search%")
                        ->orWhere('alias_name', 'ILIKE', "%$search%");
                });
            })
            ->when($brand_id, function ($query) use ($brand_id) {
                $query->where('brand_id', $brand_id);
            })
            ->when($gender_id, function ($query) use ($gender_id) {
                $query->where('gender_id', $gender_id);
            })
            ->when($event, function ($query) use ($event) {
                $query->where('d.event', $event);
            })
            ->when($sorting_ids, function ($query) use ($sorting_ids) {
                $query->whereIn('items.id', $sorting_ids);
            });

        if ($category_id) {
            $categories = StoreCategoryMap::where('store_category_id', $category_id)->get();
            $builder->where(function ($query) use ($categories) {
                $i = 0;
                foreach ($categories as $category) {
                    if ($i == 0) {
                        $query->where(function ($query) use ($category) {
                            $query->where('item_dimension.category1', $category->category1)
                                ->where('item_dimension.category2', $category->category2);
                        });
                    } else {
                        $query->orWhere(function ($query) use ($category) {
                            $query->where('item_dimension.category1', $category->category1)
                                ->where('item_dimension.category2', $category->category2);
                        });
                    }
                    $i++;
                }
            });
        }

        return $builder->paginate($limit);
    }

    public function getProductList($params)
    {
        $bindings = [];

        // =========================
        // ORDER BY
        // =========================
        $order_by = 'ORDER BY dpr.discount_price ASC NULLS LAST';

        $sort = $params['sort'] ?? null;
        if ($sort === 'price_high_to_low') {
            $order_by = 'ORDER BY dpr.discount_price DESC NULLS LAST';
        } elseif ($sort === 'price_low_to_high') {
            $order_by = 'ORDER BY dpr.discount_price ASC NULLS LAST';
        } elseif ($sort === 'new') {
            $order_by = 'ORDER BY items.created_at DESC NULLS LAST';
        }


        $location_id = $params['location_id'] ?? null;

        // =========================
        // WHERE CONDITIONS
        // =========================
        $wheres = [];

        $price_range_start = $params['price_range_start'] ?? null;
        $price_range_end = $params['price_range_end'] ?? null;

        if ($price_range_start !== null && $price_range_end !== null) {
            $wheres[] = '(dpr.discount_price BETWEEN ? AND ?)';
            $bindings[] = $price_range_start;
            $bindings[] = $price_range_end;
        }

        $whereSql = $wheres
            ? 'AND '.implode(' AND ', $wheres)
            : '';

        // =========================
        // QUERY
        // =========================
        $sql = "SELECT
                items.*,
                dp.percent,
                dp.event,
                dpr.discount_price
            FROM items
            LEFT JOIN item_dimension
                ON item_dimension.no = items.number

            -- =========================
            -- DISCOUNT PERCENT
            -- =========================
            LEFT JOIN (
                SELECT DISTINCT ON (di.item_reference_id)
                    di.item_reference_id,
                    di.percent,
                    d.created_at,
                    d.location_id,
                    CASE
                        WHEN d.valid_at IS NULL THEN 'special-offer'
                        ELSE 'limited-sale'
                    END AS event
                FROM discount_items di
                JOIN discounts d ON d.id = di.discount_id
                WHERE d.type = 'discount'
                AND (d.valid_at IS NULL OR d.valid_at <= NOW())
                AND (d.expired_at IS NULL OR d.expired_at >= NOW())
                AND (
                        ($location_id IS NOT NULL AND (d.location_id = $location_id OR d.location_id IS NULL))
                    OR ($location_id IS NULL AND d.location_id IS NULL)
                )
                ORDER BY
                    di.item_reference_id,
                    CASE
                        WHEN d.location_id = $location_id THEN 1
                        ELSE 2
                    END,
                    d.created_at DESC
            ) dp ON dp.item_reference_id = items.id

            -- =========================
            -- DISCOUNT PRICE
            -- =========================
            LEFT JOIN (
                SELECT DISTINCT ON (di.item_reference_id)
                    di.item_reference_id,
                    di.price AS discount_price,
                    d.created_at,
                    d.location_id
                FROM discount_items di
                JOIN discounts d ON d.id = di.discount_id
                WHERE d.type = 'price'
                AND (d.valid_at IS NULL OR d.valid_at <= NOW())
                AND (d.expired_at IS NULL OR d.expired_at >= NOW())
                AND (
                        ($location_id IS NOT NULL AND (d.location_id = $location_id OR d.location_id IS NULL))
                    OR ($location_id IS NULL AND d.location_id IS NULL)
                )
                ORDER BY
                    di.item_reference_id,
                    CASE
                        WHEN d.location_id = $location_id THEN 1
                        ELSE 2
                    END,
                    d.created_at DESC
            ) dpr ON dpr.item_reference_id = items.id

            WHERE items.is_publish = TRUE
            AND items.deleted_at IS NULL
            $whereSql
            $order_by
        ";


        $select= DB::select($sql, $bindings);

        return $select;
    }

    public function getMinMaxPrice()
    {
        return [
            'min' => DiscountItem::min('price'),
            'max' => DiscountItem::max('price'),
        ];
    }

    public function show($slug)
    {
        $product = Items::where('slug', $slug)
            ->when(is_int($slug), function ($query) use ($slug) {
                return $query->orWhere('id', $slug);
            })
            ->first();

        if ($product == null) {
            abort(404);
        }

        $all = session()->get('viewed_products', []);
        $all[] = $product->id;
        session()->put('viewed_products', array_unique($all));

        return $product;
    }

    public function viewed_products($except_ids = [])
    {
        $ids = session()->get('viewed_products', []);
        if (empty($ids)) {
            return collect();
        }

        // Remove except_ids from the list
        $ids = array_diff($ids, (array) $except_ids);

        return Items::whereIn('id', $ids)->inRandomOrder()->take(10)->get();
    }
}
