<?php

declare(strict_types=1);

namespace FatBottom\Services;

use FatBottom\Core\Database;
use RuntimeException;

final class OrderService
{
    public function __construct(
        private readonly Database $db,
        private readonly PaymentGateway $payments,
        private readonly CustomerService $customers
    ) {
    }

    public function totals(array $cart): array
    {
        $subtotal = (int) $cart['subtotal_cents'];
        $taxRate = (int) $this->db->fetch(
            'SELECT COALESCE(SUM(rate_basis_points), 0) AS total_rate FROM tax_rates WHERE active = 1'
        )['total_rate'];
        $tax = (int) round($subtotal * $taxRate / 10000);
        return [
            'subtotal_cents' => $subtotal,
            'tax_rate_basis_points' => $taxRate,
            'tax_cents' => $tax,
            'total_cents' => $subtotal + $tax,
        ];
    }

    public function place(array $cart, array $customer, ?int $userId, string $sourceId): array
    {
        if (empty($cart['items'])) {
            throw new RuntimeException('Your cart is empty.');
        }

        $totals = $this->totals($cart);
        $orderNumber = 'FBG-' . date('ymd') . '-'
            . strtoupper(substr(hash('sha256', (string) $cart['token']), 0, 6));
        $payment = $this->payments->charge($sourceId, $totals['total_cents'], $orderNumber);

        $pdo = $this->db->pdo();
        $pdo->beginTransaction();
        try {
            $customerId = $this->customers->capture($customer, $userId);
            $trackingToken = bin2hex(random_bytes(24));
            $statement = $pdo->prepare(
                'INSERT INTO orders
                    (order_number, user_id, customer_id, cart_id, tracking_token,
                     customer_name, customer_email, customer_phone,
                     order_type, status, payment_status, payment_provider, payment_reference,
                     subtotal_cents, tax_cents, total_cents, special_instructions, pickup_time)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
            );
            $statement->execute([
                $orderNumber,
                $userId,
                $customerId,
                (int) $cart['id'],
                $trackingToken,
                $customer['customer_name'],
                $customer['customer_email'],
                $customer['customer_phone'],
                'pickup',
                'pending',
                'paid',
                $payment['provider'],
                $payment['reference'],
                $totals['subtotal_cents'],
                $totals['tax_cents'],
                $totals['total_cents'],
                $customer['special_instructions'],
                $customer['pickup_time'] ?: null,
            ]);
            $orderId = (int) $pdo->lastInsertId();

            $itemStatement = $pdo->prepare(
                'INSERT INTO order_items
                    (order_id, menu_item_id, item_name, quantity, unit_price_cents, line_total_cents, notes)
                 VALUES (?, ?, ?, ?, ?, ?, ?)'
            );
            foreach ($cart['items'] as $item) {
                $itemStatement->execute([
                    $orderId,
                    (int) $item['menu_item_id'],
                    $item['name'],
                    (int) $item['quantity'],
                    (int) $item['unit_price_cents'],
                    (int) $item['quantity'] * (int) $item['unit_price_cents'],
                    $item['notes'],
                ]);
            }

            $pdo->prepare(
                'INSERT INTO order_events
                    (order_id, user_id, event_type, details, status, customer_visible)
                 VALUES (?, ?, ?, ?, ?, 1)'
            )->execute([
                $orderId,
                $userId,
                'order_placed',
                'Online pickup order paid successfully and is awaiting staff acceptance.',
                'pending',
            ]);
            $pdo->prepare(
                "UPDATE carts SET status = 'converted', converted_at = CURRENT_TIMESTAMP WHERE id = ?"
            )->execute([(int) $cart['id']]);
            $this->customers->refresh($customerId);
            $pdo->commit();
        } catch (\Throwable $error) {
            $pdo->rollBack();
            throw $error;
        }

        return $this->db->fetch('SELECT * FROM orders WHERE id = ?', [$orderId]) ?? [];
    }
}
