<?php

require_once BASE_PATH
    . '/app/models/Cart.php';

require_once BASE_PATH
    . '/app/models/CartItem.php';

require_once BASE_PATH
    . '/app/models/Product.php';


class CartController
{
    private Cart $cartModel;

    private CartItem $cartItemModel;

    private Product $productModel;


    public function __construct()
    {
        $this->cartModel =
            new Cart();

        $this->cartItemModel =
            new CartItem();

        $this->productModel =
            new Product();
    }


    // ========================================================
    // CART PAGE
    // ========================================================

    public function index(): void
    {
        $this->requireGuestOrCustomer();

        $items =
            $this->getCurrentCartItems();


        $subtotal = 0;


        foreach ($items as &$item) {

            $item['line_total'] =
                (float)
                $item['current_price']

                *

                (int)
                $item['quantity'];


            $subtotal +=
                $item['line_total'];
        }

        unset($item);


        $cartCount =
            $this->calculateCartCount();


        $_SESSION['cart_count'] =
            $cartCount;


        require BASE_PATH
            . '/app/views/cart/index.php';
    }


    // ========================================================
    // ADD TO CART
    // ========================================================

    public function add(): void
    {
        $this->requireGuestOrCustomer();

        $this->requirePost();

        $this->validateCsrf();


        $productId =
            (int)
            ($_POST['product_id'] ?? 0);


        $quantity =
            max(
                1,
                (int)
                ($_POST['quantity'] ?? 1)
            );


        $product =
            $this->productModel
                ->findById($productId);


        if (!$product) {

            $this->flashError(
                'Sản phẩm không tồn tại.'
            );

            $this->redirectToProducts();
        }


        if (
            $product['status']
            !== 'active'
        ) {

            $this->flashError(
                'Sản phẩm hiện không thể mua.'
            );

            $this->redirectToProducts();
        }


        $stock =
            (int)
            $product['stock_quantity'];


        if ($stock <= 0) {

            $this->flashError(
                'Sản phẩm đã hết hàng.'
            );

            $this->redirectToProduct(
                $product['slug']
            );
        }


        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cartId =
                $this->cartModel
                    ->getOrCreate(
                        $customerId
                    );


            $current =
                $this->cartItemModel
                    ->getQuantity(
                        $cartId,
                        $productId
                    );


            $newQuantity =
                $current + $quantity;


            if ($newQuantity > $stock) {

                $this->flashError(
                    'Kho chỉ còn '
                    . $stock
                    . ' sản phẩm.'
                );

                $this->redirectToProduct(
                    $product['slug']
                );
            }


            $this->cartItemModel
                ->setQuantity(
                    $cartId,
                    $productId,
                    $newQuantity
                );

        } else {

            // Guest cart
            $_SESSION['guest_cart']
                ??= [];


            $current =
                (int)
                (
                    $_SESSION[
                        'guest_cart'
                    ][$productId]
                    ?? 0
                );


            $newQuantity =
                $current + $quantity;


            if ($newQuantity > $stock) {

                $this->flashError(
                    'Kho chỉ còn '
                    . $stock
                    . ' sản phẩm.'
                );

                $this->redirectToProduct(
                    $product['slug']
                );
            }


            $_SESSION[
                'guest_cart'
            ][$productId] =
                $newQuantity;
        }


        $this->syncCartCount();


        $this->flashSuccess(
            'Đã thêm sản phẩm vào giỏ hàng.'
        );


        header(
            'Location: '
            . BASE_URL
            . '/?url=cart'
        );

        exit;
    }


    // ========================================================
    // UPDATE QUANTITY
    // ========================================================

    public function update(): void
    {
        $this->requireGuestOrCustomer();

        $this->requirePost();

        $this->validateCsrf();


        $productId =
            (int)
            ($_POST['product_id'] ?? 0);


        $quantity =
            (int)
            ($_POST['quantity'] ?? 1);


        $product =
            $this->productModel
                ->findById($productId);


        if (!$product) {

            $this->flashError(
                'Sản phẩm không tồn tại.'
            );

            $this->redirectToCart();
        }


        if ($quantity <= 0) {

            $this->removeItem(
                $productId
            );

            $this->syncCartCount();

            $this->redirectToCart();
        }


        $stock =
            (int)
            $product['stock_quantity'];


        if ($quantity > $stock) {

            $this->flashError(
                'Kho chỉ còn '
                . $stock
                . ' sản phẩm.'
            );

            $this->redirectToCart();
        }


        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cartId =
                $this->cartModel
                    ->getOrCreate(
                        $customerId
                    );


            $this->cartItemModel
                ->setQuantity(
                    $cartId,
                    $productId,
                    $quantity
                );

        } else {

            $_SESSION[
                'guest_cart'
            ][$productId] =
                $quantity;
        }


        $this->syncCartCount();


        $this->flashSuccess(
            'Đã cập nhật giỏ hàng.'
        );


        $this->redirectToCart();
    }


    // ========================================================
    // REMOVE
    // ========================================================

    public function remove(): void
    {
        $this->requireGuestOrCustomer();

        $this->requirePost();

        $this->validateCsrf();


        $productId =
            (int)
            ($_POST['product_id'] ?? 0);


        $this->removeItem(
            $productId
        );


        $this->syncCartCount();


        $this->flashSuccess(
            'Đã xóa sản phẩm khỏi giỏ.'
        );


        $this->redirectToCart();
    }


    // ========================================================
    // CLEAR
    // ========================================================

    public function clear(): void
    {
        $this->requireGuestOrCustomer();

        $this->requirePost();

        $this->validateCsrf();


        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cart =
                $this->cartModel
                    ->findByCustomerId(
                        $customerId
                    );


            if ($cart) {

                $this->cartModel
                    ->clear(
                        (int)
                        $cart['id']
                    );
            }

        } else {

            $_SESSION['guest_cart'] =
                [];
        }


        $_SESSION['cart_count'] = 0;


        $this->flashSuccess(
            'Đã xóa toàn bộ giỏ hàng.'
        );


        $this->redirectToCart();
    }


    // ========================================================
    // GET CURRENT CART
    // ========================================================

    private function getCurrentCartItems(): array
    {
        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cart =
                $this->cartModel
                    ->findByCustomerId(
                        $customerId
                    );


            if (!$cart) {

                return [];
            }


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


        $guestCart =
            $_SESSION['guest_cart']
            ?? [];


        $items = [];


        foreach (
            $guestCart
            as $productId => $quantity
        ) {

            $product =
                $this->productModel
                    ->findById(
                        (int)
                        $productId
                    );


            if (!$product) {

                unset(
                    $_SESSION[
                        'guest_cart'
                    ][$productId]
                );

                continue;
            }


            $product['product_id'] =
                (int)
                $product['id'];


            $product['quantity'] =
                (int)
                $quantity;


            $items[] =
                $product;
        }


        return $items;
    }


    // ========================================================
    // REMOVE INTERNAL
    // ========================================================

    private function removeItem(
        int $productId
    ): void {

        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cart =
                $this->cartModel
                    ->findByCustomerId(
                        $customerId
                    );


            if ($cart) {

                $this->cartItemModel
                    ->remove(
                        (int)
                        $cart['id'],
                        $productId
                    );
            }

        } else {

            unset(
                $_SESSION[
                    'guest_cart'
                ][$productId]
            );
        }
    }


    // ========================================================
    // CART COUNT
    // ========================================================

    private function calculateCartCount(): int
    {
        if ($this->isCustomer()) {

            $customerId =
                (int)
                $_SESSION['user']['id'];


            $cart =
                $this->cartModel
                    ->findByCustomerId(
                        $customerId
                    );


            if (!$cart) {

                return 0;
            }


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


        return array_sum(
            $_SESSION['guest_cart']
            ?? []
        );
    }


    private function syncCartCount(): void
    {
        $_SESSION['cart_count'] =
            $this->calculateCartCount();
    }


    // ========================================================
    // AUTH
    // ========================================================

    private function isCustomer(): bool
    {
        return isset(
            $_SESSION['user']
        )

        && (
            $_SESSION['user']['role']
            ?? null
        ) === 'customer'

        && isset(
            $_SESSION['user']['id']
        );
    }


    private function requireGuestOrCustomer(): void
    {
        if (
            isset($_SESSION['user'])
            && !$this->isCustomer()
        ) {

            $_SESSION['flash_error'] =
                'Tài khoản quản trị không sử dụng giỏ hàng mua sắm.';

            $this->redirectToProducts();
        }
    }


    // ========================================================
    // SECURITY
    // ========================================================

    private function requirePost(): void
    {
        if (
            $_SERVER[
                'REQUEST_METHOD'
            ] !== 'POST'
        ) {

            http_response_code(405);

            exit(
                'Method Not Allowed'
            );
        }
    }


    private function validateCsrf(): void
    {
        $token =
            $_POST['_token']
            ?? '';


        $sessionToken =
            $_SESSION['csrf_token']
            ?? '';


        if (
            $token === ''
            || $sessionToken === ''
            || !hash_equals(
                $sessionToken,
                $token
            )
        ) {

            http_response_code(403);

            exit(
                'Yêu cầu không hợp lệ.'
            );
        }
    }


    // ========================================================
    // FLASH
    // ========================================================

    private function flashSuccess(
        string $message
    ): void {

        $_SESSION[
            'flash_success'
        ] = $message;
    }


    private function flashError(
        string $message
    ): void {

        $_SESSION[
            'flash_error'
        ] = $message;
    }


    // ========================================================
    // REDIRECT
    // ========================================================

    private function redirectToCart(): never
    {
        header(
            'Location: '
            . BASE_URL
            . '/?url=cart'
        );

        exit;
    }


    private function redirectToProducts(): never
    {
        header(
            'Location: '
            . BASE_URL
            . '/?url=products'
        );

        exit;
    }


    private function redirectToProduct(
        string $slug
    ): never {

        header(
            'Location: '
            . BASE_URL
            . '/?url=product&slug='
            . urlencode($slug)
        );

        exit;
    }
}
