<?php

declare(strict_types=1);

namespace FatBottom\Controllers;

use FatBottom\Core\Auth;
use FatBottom\Core\Config;
use FatBottom\Core\Database;
use FatBottom\Core\Http;
use FatBottom\Core\Security;
use FatBottom\Core\View;
use FatBottom\Services\CartService;
use FatBottom\Services\OrderService;
use FatBottom\Services\OrderStatusService;

final class StoreController extends BaseController
{
    public function __construct(
        Config $config,
        Auth $auth,
        CartService $cart,
        private readonly Database $db,
        private readonly OrderService $orders,
        private readonly OrderStatusService $orderStatuses
    ) {
        parent::__construct($config, $auth, $cart);
    }

    public function home(): void
    {
        $categories = $this->menuCategories(true);
        $specials = $this->db->fetchAll(
            "SELECT s.*, mi.name AS item_name
             FROM specials s
             LEFT JOIN menu_items mi ON mi.id = s.menu_item_id
             WHERE s.active = 1
               AND (s.starts_at IS NULL OR s.starts_at <= CURRENT_TIMESTAMP)
               AND (s.ends_at IS NULL OR s.ends_at >= CURRENT_TIMESTAMP)
             ORDER BY s.display_order, s.id"
        );
        $featured = $this->db->fetchAll(
            'SELECT mi.*, mc.name AS category_name
             FROM menu_items mi
             JOIN menu_categories mc ON mc.id = mi.category_id
             WHERE mi.active = 1 AND mc.active = 1 AND mi.featured = 1
             ORDER BY mi.display_order, mi.id LIMIT 6'
        );

        View::render('store/home', $this->shared([
            'title' => 'Keyser comfort food, ready when you are',
            'categories' => $categories,
            'specials' => $specials,
            'featured' => $featured,
        ]));
    }

    public function menu(): void
    {
        $query = Security::clean((string) ($_GET['q'] ?? ''));
        $categories = $this->menuCategories(false, $query);
        View::render('store/menu', $this->shared([
            'title' => 'Order Online',
            'categories' => $categories,
            'query' => $query,
        ]));
    }

    public function addToCart(): void
    {
        Security::verifyCsrf();
        $user = $this->auth->user();
        $added = $this->cart->add(
            (int) ($_POST['menu_item_id'] ?? 0),
            (int) ($_POST['quantity'] ?? 1),
            Security::clean((string) ($_POST['notes'] ?? '')),
            $user ? (int) $user['id'] : null
        );

        Http::flash($added ? 'success' : 'error', $added ? 'Added to your order.' : 'That item is not currently available.');
        $returnTo = (string) ($_POST['return_to'] ?? '/menu');
        Http::redirect(str_starts_with($returnTo, '/') ? $returnTo : '/menu');
    }

    public function cart(): void
    {
        $user = $this->auth->user();
        $details = $this->cart->details($user ? (int) $user['id'] : null);
        View::render('store/cart', $this->shared([
            'title' => 'Your Order',
            'cart' => $details,
            'totals' => $this->orders->totals($details),
        ]));
    }

    public function updateCart(): void
    {
        Security::verifyCsrf();
        $user = $this->auth->user();
        $quantities = isset($_POST['quantity']) && is_array($_POST['quantity'])
            ? $_POST['quantity']
            : [];
        $this->cart->update($quantities, $user ? (int) $user['id'] : null);
        Http::flash('success', 'Your order has been updated.');
        Http::redirect('/cart');
    }

    public function removeFromCart(): void
    {
        Security::verifyCsrf();
        $user = $this->auth->user();
        $this->cart->remove((int) ($_POST['cart_item_id'] ?? 0), $user ? (int) $user['id'] : null);
        Http::flash('success', 'Item removed.');
        Http::redirect('/cart');
    }

    public function checkout(): void
    {
        $user = $this->auth->user();
        $details = $this->cart->details($user ? (int) $user['id'] : null);
        if (empty($details['items'])) {
            Http::flash('warning', 'Add something delicious before checking out.');
            Http::redirect('/menu');
        }

        View::render('store/checkout', $this->shared([
            'title' => 'Checkout',
            'cart' => $details,
            'totals' => $this->orders->totals($details),
            'taxRates' => $this->db->fetchAll('SELECT * FROM tax_rates WHERE active = 1 ORDER BY id'),
            'squareEnabled' => (bool) $this->config->get('square.enabled', false),
            'squareAppId' => (string) $this->config->get('square.application_id', ''),
            'squareLocationId' => (string) $this->config->get('square.location_id', ''),
            'squareEnvironment' => (string) $this->config->get('square.environment', 'sandbox'),
        ]));
    }

    public function placeOrder(): void
    {
        Security::verifyCsrf();
        $user = $this->auth->user();
        $cart = $this->cart->details($user ? (int) $user['id'] : null);
        $input = [
            'customer_name' => Security::clean((string) ($_POST['customer_name'] ?? '')),
            'customer_email' => strtolower(Security::clean((string) ($_POST['customer_email'] ?? ''))),
            'customer_phone' => Security::clean((string) ($_POST['customer_phone'] ?? '')),
            'pickup_time' => Security::clean((string) ($_POST['pickup_time'] ?? '')),
            'special_instructions' => Security::clean((string) ($_POST['special_instructions'] ?? '')),
        ];

        if (
            $input['customer_name'] === ''
            || !filter_var($input['customer_email'], FILTER_VALIDATE_EMAIL)
            || $input['customer_phone'] === ''
        ) {
            Http::old($input);
            Http::flash('error', 'Name, a valid email address, and phone number are required.');
            Http::redirect('/checkout');
        }
        if (!(bool) $this->config->get('ordering.accepting_orders', true)) {
            Http::flash('error', 'Online ordering is currently paused.');
            Http::redirect('/cart');
        }

        try {
            $order = $this->orders->place(
                $cart,
                $input,
                $user ? (int) $user['id'] : null,
                (string) ($_POST['square_token'] ?? '')
            );
            try {
                $this->orderStatuses->sendStatusEmail($order, 'pending');
            } catch (\Throwable) {
                Http::flash('warning', 'Your order was placed, but the confirmation email could not be sent.');
            }
            setcookie('fatbottom_cart', '', ['expires' => time() - 3600, 'path' => '/']);
            $_SESSION['last_order_id'] = (int) $order['id'];
            Http::redirect('/order/complete');
        } catch (\Throwable $error) {
            Http::old($input);
            Http::flash('error', $error->getMessage());
            Http::redirect('/checkout');
        }
    }

    public function orderComplete(): void
    {
        $orderId = (int) ($_SESSION['last_order_id'] ?? 0);
        $order = $this->db->fetch('SELECT * FROM orders WHERE id = ?', [$orderId]);
        if ($order === null) {
            Http::redirect('/');
        }
        $items = $this->db->fetchAll('SELECT * FROM order_items WHERE order_id = ?', [$orderId]);
        View::render('store/order-complete', $this->shared([
            'title' => 'Order Received',
            'order' => $order,
            'items' => $items,
            'trackingUrl' => $this->orderStatuses->trackingUrl($order),
        ]));
    }

    public function orderTracker(): void
    {
        $orderNumber = Security::clean((string) ($_GET['order'] ?? ''));
        $token = (string) ($_GET['token'] ?? '');
        $order = $this->db->fetch('SELECT * FROM orders WHERE order_number = ?', [$orderNumber]);
        if ($order === null) {
            Http::abort(404, 'Order not found.');
        }

        $user = $this->auth->user();
        $ownsOrder = $user !== null && (
            (int) ($order['user_id'] ?? 0) === (int) $user['id']
            || strtolower((string) $order['customer_email']) === strtolower((string) $user['email'])
        );
        $validToken = $token !== ''
            && (string) $order['tracking_token'] !== ''
            && hash_equals((string) $order['tracking_token'], $token);
        if (!$ownsOrder && !$validToken) {
            Http::abort(403, 'This tracking link is invalid.');
        }

        View::render('store/order-tracker', $this->shared([
            'title' => 'Track ' . $order['order_number'],
            'order' => $order,
            'events' => $this->db->fetchAll(
                "SELECT * FROM order_events
                 WHERE order_id = ? AND (status <> '' OR customer_visible = 1)
                 ORDER BY created_at, id",
                [(int) $order['id']]
            ),
            'items' => $this->db->fetchAll(
                'SELECT * FROM order_items WHERE order_id = ? ORDER BY id',
                [(int) $order['id']]
            ),
        ]));
    }

    private function menuCategories(bool $homepage, string $query = ''): array
    {
        $categories = $this->db->fetchAll(
            'SELECT * FROM menu_categories WHERE active = 1 ORDER BY display_order, name'
        );
        foreach ($categories as &$category) {
            $parameters = [(int) $category['id']];
            $where = 'category_id = ? AND active = 1';
            if ($query !== '') {
                $where .= ' AND (name LIKE ? OR description LIKE ?)';
                $parameters[] = '%' . $query . '%';
                $parameters[] = '%' . $query . '%';
            }
            $limit = $homepage ? ' LIMIT 4' : '';
            $category['items'] = $this->db->fetchAll(
                "SELECT * FROM menu_items WHERE {$where} ORDER BY display_order, name{$limit}",
                $parameters
            );
        }
        unset($category);

        return array_values(array_filter(
            $categories,
            static fn (array $category): bool => $category['items'] !== []
        ));
    }
}
