<?php

namespace App\Services;

use App\Models\DiscountCode;
use App\Models\Product;
use App\Models\ProductVariant;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;

class CartService
{
    private const SESSION_KEY = 'biosupply_cart';

    public function get(Request $request): array
    {
        $items = Session::get(self::SESSION_KEY, []);
        return $this->buildCart($items, $request);
    }

    public function add(Request $request, int $productId, ?int $variantId, int $quantity): array
    {
        $items = Session::get(self::SESSION_KEY, []);
        $key = $this->itemKey($productId, $variantId);

        if (isset($items[$key])) {
            $items[$key]['quantity'] += $quantity;
        } else {
            $product = Product::with('primaryImage')->findOrFail($productId);
            $variant = $variantId ? ProductVariant::findOrFail($variantId) : null;

            $price = $variant ? $variant->price : $product->price;
            $inStock = $variant ? $variant->stock_quantity > 0 : $product->is_in_stock;

            $items[$key] = [
                'product_id' => $productId,
                'variant_id' => $variantId,
                'name' => $product->name,
                'variant_name' => $variant?->name,
                'price' => (float) $price,
                'quantity' => $quantity,
                'image' => $product->primaryImage?->url,
                'slug' => $product->slug,
                'is_preorder' => !$inStock && $product->allow_preorder,
            ];
        }

        Session::put(self::SESSION_KEY, $items);
        return $this->buildCart($items, $request);
    }

    public function update(Request $request, int $productId, ?int $variantId, int $quantity): array
    {
        $items = Session::get(self::SESSION_KEY, []);
        $key = $this->itemKey($productId, $variantId);

        if ($quantity <= 0) {
            unset($items[$key]);
        } elseif (isset($items[$key])) {
            $items[$key]['quantity'] = $quantity;
        }

        Session::put(self::SESSION_KEY, $items);
        return $this->buildCart($items, $request);
    }

    public function remove(Request $request, int $productId, ?int $variantId): array
    {
        $items = Session::get(self::SESSION_KEY, []);
        $key = $this->itemKey($productId, $variantId);
        unset($items[$key]);
        Session::put(self::SESSION_KEY, $items);
        return $this->buildCart($items, $request);
    }

    public function applyDiscount(Request $request, string $code, float $subtotal = 0): array
    {
        $discount = DiscountCode::where('code', strtoupper($code))->first();

        if (!$discount || !$discount->isValid()) {
            throw new \InvalidArgumentException('Invalid or expired discount code.');
        }

        if ($discount->user_id && optional($request->user())->id !== $discount->user_id) {
            throw new \InvalidArgumentException('This discount code is not valid for your account.');
        }

        $discountAmount = $discount->calculateDiscount($subtotal);

        return [
            'discount_code'   => strtoupper($code),
            'discount_amount' => round($discountAmount, 2),
            'type'            => $discount->type,
            'value'           => (float) $discount->value,
        ];
    }

    public function removeDiscount(Request $request): array
    {
        Session::forget('cart_discount_code');
        return $this->get($request);
    }

    public function clear(): void
    {
        Session::forget([self::SESSION_KEY, 'cart_discount_code']);
    }

    public static function bulkDiscount(int $quantity): float
    {
        if ($quantity >= 3) return 0.15;
        if ($quantity >= 2) return 0.10;
        return 0.0;
    }

    private function buildCart(array $items, Request $request): array
    {
        // Apply per-item bulk discount before summing
        $enriched = [];
        foreach ($items as $item) {
            $disc = self::bulkDiscount($item['quantity']);
            $item['bulk_discount_pct'] = $disc > 0 ? (int)($disc * 100) : null;
            $item['effective_price']   = round($item['price'] * (1 - $disc), 2);
            $item['line_total']        = round($item['effective_price'] * $item['quantity'], 2);
            $enriched[] = $item;
        }
        $subtotal = array_sum(array_column($enriched, 'line_total'));

        $discountCode = Session::get('cart_discount_code');
        $discountAmount = 0;

        if ($discountCode) {
            $discount = DiscountCode::where('code', strtoupper($discountCode))->first();
            if ($discount && $discount->isValid()) {
                $discountAmount = $discount->calculateDiscount($subtotal);
            } else {
                Session::forget('cart_discount_code');
                $discountCode = null;
            }
        }

        $loyaltyPoints = 0;
        if ($request->user()) {
            $loyaltyPoints = $request->user()->loyalty_points;
        }

        return [
            'items' => array_values($enriched),
            'item_count' => array_sum(array_column($enriched, 'quantity')),
            'subtotal' => round($subtotal, 2),
            'discount_code' => $discountCode,
            'discount_amount' => round($discountAmount, 2),
            'loyalty_points_available' => $loyaltyPoints,
            'total' => round(max(0, $subtotal - $discountAmount), 2),
        ];
    }

    private function itemKey(int $productId, ?int $variantId): string
    {
        return "{$productId}_{$variantId}";
    }
}
