<?php

declare(strict_types=1);

namespace FatBottom\Services;

use FatBottom\Core\Database;

final class CartService
{
    public function __construct(private readonly Database $db)
    {
    }

    public function current(?int $userId = null): array
    {
        $token = $_COOKIE['fatbottom_cart'] ?? '';
        $cart = null;
        if (is_string($token) && $token !== '') {
            $cart = $this->db->fetch('SELECT * FROM carts WHERE token = ? AND status = ?', [$token, 'active']);
        }

        if ($cart === null) {
            $token = bin2hex(random_bytes(24));
            $this->db->execute(
                'INSERT INTO carts (token, user_id, status) VALUES (?, ?, ?)',
                [$token, $userId, 'active']
            );
            setcookie('fatbottom_cart', $token, [
                'expires' => time() + 60 * 60 * 24 * 30,
                'path' => '/',
                'secure' => !empty($_SERVER['HTTPS']),
                'httponly' => true,
                'samesite' => 'Lax',
            ]);
            $cart = $this->db->fetch('SELECT * FROM carts WHERE token = ?', [$token]);
        } elseif ($userId !== null && empty($cart['user_id'])) {
            $this->db->execute('UPDATE carts SET user_id = ? WHERE id = ?', [$userId, (int) $cart['id']]);
            $cart['user_id'] = $userId;
        }

        $this->touch((int) $cart['id']);
        return $cart;
    }

    public function add(int $menuItemId, int $quantity, string $notes, ?int $userId = null): bool
    {
        $item = $this->db->fetch('SELECT * FROM menu_items WHERE id = ? AND active = 1', [$menuItemId]);
        if ($item === null) {
            return false;
        }

        $special = $this->db->fetch(
            "SELECT price_cents FROM specials
             WHERE menu_item_id = ? AND active = 1 AND price_cents IS NOT NULL
               AND (starts_at IS NULL OR starts_at <= CURRENT_TIMESTAMP)
               AND (ends_at IS NULL OR ends_at >= CURRENT_TIMESTAMP)
             ORDER BY price_cents ASC LIMIT 1",
            [$menuItemId]
        );
        $unitPrice = $special !== null
            ? min((int) $item['price_cents'], (int) $special['price_cents'])
            : (int) $item['price_cents'];

        $cart = $this->current($userId);
        $notes = trim(substr($notes, 0, 240));
        $existing = $this->db->fetch(
            'SELECT * FROM cart_items WHERE cart_id = ? AND menu_item_id = ? AND notes = ?',
            [(int) $cart['id'], $menuItemId, $notes]
        );

        if ($existing) {
            $this->db->execute(
                'UPDATE cart_items SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
                [min(20, (int) $existing['quantity'] + max(1, $quantity)), (int) $existing['id']]
            );
        } else {
            $this->db->execute(
                'INSERT INTO cart_items (cart_id, menu_item_id, quantity, unit_price_cents, notes)
                 VALUES (?, ?, ?, ?, ?)',
                [(int) $cart['id'], $menuItemId, min(20, max(1, $quantity)), $unitPrice, $notes]
            );
        }

        $this->recalculate((int) $cart['id']);
        return true;
    }

    public function update(array $quantities, ?int $userId = null): void
    {
        $cart = $this->current($userId);
        foreach ($quantities as $itemId => $quantity) {
            $itemId = (int) $itemId;
            $quantity = (int) $quantity;
            if ($quantity <= 0) {
                $this->db->execute('DELETE FROM cart_items WHERE id = ? AND cart_id = ?', [$itemId, (int) $cart['id']]);
            } else {
                $this->db->execute(
                    'UPDATE cart_items SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND cart_id = ?',
                    [min(20, $quantity), $itemId, (int) $cart['id']]
                );
            }
        }
        $this->recalculate((int) $cart['id']);
    }

    public function remove(int $cartItemId, ?int $userId = null): void
    {
        $cart = $this->current($userId);
        $this->db->execute('DELETE FROM cart_items WHERE id = ? AND cart_id = ?', [$cartItemId, (int) $cart['id']]);
        $this->recalculate((int) $cart['id']);
    }

    public function details(?int $userId = null): array
    {
        $cart = $this->current($userId);
        $items = $this->db->fetchAll(
            'SELECT ci.*, mi.name, mi.description, mi.active
             FROM cart_items ci
             JOIN menu_items mi ON mi.id = ci.menu_item_id
             WHERE ci.cart_id = ?
             ORDER BY ci.id',
            [(int) $cart['id']]
        );
        $cart['items'] = $items;
        $cart['item_count'] = array_sum(array_map(static fn (array $item): int => (int) $item['quantity'], $items));
        return $cart;
    }

    private function touch(int $cartId): void
    {
        $this->db->execute('UPDATE carts SET last_seen_at = CURRENT_TIMESTAMP WHERE id = ?', [$cartId]);
    }

    private function recalculate(int $cartId): void
    {
        $subtotal = (int) $this->db->fetch(
            'SELECT COALESCE(SUM(quantity * unit_price_cents), 0) AS subtotal
             FROM cart_items WHERE cart_id = ?',
            [$cartId]
        )['subtotal'];
        $this->db->execute(
            'UPDATE carts SET subtotal_cents = ?, last_seen_at = CURRENT_TIMESTAMP WHERE id = ?',
            [$subtotal, $cartId]
        );
    }
}
