<?php

declare(strict_types=1);

namespace App\Modules\Sales\Application\Services;

use PDO;

final class PosCartService
{
    public function ensureSessionState(): void
    {
        if (!isset($_SESSION['cart']) || !is_array($_SESSION['cart'])) {
            $_SESSION['cart'] = [];
        }
    }

    public function normalizeEntry(mixed $entry): array
    {
        if (is_array($entry)) {
            $qty = round((float)($entry['qty'] ?? 0), 3);
            $discountType = strtoupper(trim((string)($entry['discount_type'] ?? 'VALUE')));
            if (!in_array($discountType, ['VALUE', 'PERCENT'], true)) {
                $discountType = 'VALUE';
            }
            $discountValue = round(max(0, (float)($entry['discount_value'] ?? 0)), 2);

            return [
                'qty' => $qty,
                'discount_type' => $discountType,
                'discount_value' => $discountValue,
            ];
        }

        return [
            'qty' => round((float)$entry, 3),
            'discount_type' => 'VALUE',
            'discount_value' => 0.0,
        ];
    }

    public function entryQty(mixed $entry): float
    {
        return (float)($this->normalizeEntry($entry)['qty'] ?? 0.0);
    }

    public function setItem(int $itemId, float $qty, ?string $discountType = null, ?float $discountValue = null): void
    {
        $this->ensureSessionState();
        $current = $this->normalizeEntry($_SESSION['cart'][$itemId] ?? 0);
        if ($discountType !== null) {
            $current['discount_type'] = in_array(strtoupper($discountType), ['VALUE', 'PERCENT'], true) ? strtoupper($discountType) : 'VALUE';
        }
        if ($discountValue !== null) {
            $current['discount_value'] = round(max(0, (float)$discountValue), 2);
        }
        $current['qty'] = round((float)$qty, 3);

        if ($current['qty'] > 0) {
            $_SESSION['cart'][$itemId] = $current;
            return;
        }

        unset($_SESSION['cart'][$itemId]);
    }

    public function removeItem(int $itemId): void
    {
        $this->ensureSessionState();
        unset($_SESSION['cart'][$itemId]);
    }

    public function clear(): void
    {
        $_SESSION['cart'] = [];
    }

    public function all(): array
    {
        $this->ensureSessionState();
        return $_SESSION['cart'];
    }

    public function itemDiscount(float $baseTotal, string $type, float $value): array
    {
        $type = strtoupper(trim($type));
        if (!in_array($type, ['VALUE', 'PERCENT'], true)) {
            $type = 'VALUE';
        }
        $value = max(0, $value);

        if ($type === 'PERCENT') {
            if ($value > 100) {
                $value = 100;
            }
            $discount = round($baseTotal * ($value / 100), 2);
        } else {
            if ($value > $baseTotal) {
                $value = $baseTotal;
            }
            $discount = round($value, 2);
        }

        return [$type, round($value, 2), $discount, round(max(0, $baseTotal - $discount), 2)];
    }

    public function snapshot(PDO $pdo): array
    {
        $cart = $this->all();
        $cartLines = [];
        $cartTotal = 0.0;
        $cartCount = 0.0;

        if ($cart) {
            $ids = array_map('intval', array_keys($cart));
            $in = implode(',', array_fill(0, count($ids), '?'));
            $st = $pdo->prepare("SELECT id, name, barcode, price, cost FROM items WHERE id IN ($in)");
            $st->execute($ids);
            $map = [];
            foreach ($st->fetchAll() as $row) {
                $map[(int)$row['id']] = $row;
            }

            foreach ($cart as $id => $entryRaw) {
                if (!isset($map[(int)$id])) {
                    continue;
                }
                $entry = $this->normalizeEntry($entryRaw);
                $price = (float)$map[(int)$id]['price'];
                $qty = (float)$entry['qty'];
                if ($qty <= 0) {
                    continue;
                }
                $baseTotal = round($price * $qty, 2);
                [$discountType, $discountValue, $lineDiscount, $lineTotal] = $this->itemDiscount(
                    $baseTotal,
                    (string)$entry['discount_type'],
                    (float)$entry['discount_value']
                );
                $cartTotal += $lineTotal;
                $cartCount += $qty;
                $cartLines[] = [
                    'id' => (int)$id,
                    'name' => (string)$map[(int)$id]['name'],
                    'barcode' => (string)($map[(int)$id]['barcode'] ?? ''),
                    'qty' => $qty,
                    'price' => $price,
                    'base_total' => $baseTotal,
                    'discount_type' => $discountType,
                    'discount_value' => $discountValue,
                    'discount_amount' => $lineDiscount,
                    'line_total' => $lineTotal,
                ];
            }
        }

        return [
            'cart' => $cart,
            'cart_lines' => $cartLines,
            'cart_total' => round($cartTotal, 2),
            'cart_count' => round($cartCount, 3),
        ];
    }

    public function json(PDO $pdo, bool $ok, string $message = '', int $status = 200): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        $snap = $this->snapshot($pdo);
        echo json_encode([
            'ok' => $ok,
            'message' => $message,
            'cart_lines' => $snap['cart_lines'],
            'cart_total' => $snap['cart_total'],
            'cart_count' => $snap['cart_count'],
            'cart_size' => count($snap['cart_lines']),
        ], JSON_UNESCAPED_UNICODE);
        exit;
    }
}
