<?php

namespace BitApps\PiPro\src\Integrations\FluentCart\Services;

use BitApps\Pi\src\Flow\NodeInfoProvider;
use BitApps\PiPro\src\Integrations\FluentCart\FluentCartHelper;
use FluentCart\App\Models\Order;
use FluentCart\App\Models\OrderItem;

if (!\defined('ABSPATH')) {
    exit;
}

final class OrderService
{
    private $nodeInfoProvider;

    public function __construct(NodeInfoProvider $nodeInfoProvider)
    {
        $this->nodeInfoProvider = $nodeInfoProvider;
    }

    public function getAllOrder(): array
    {
        if ($validationResponse = FluentCartHelper::validateClassExistence('order')) {
            return $validationResponse;
        }

        $orders = Order::all();
        $data = ['orders' => FluentCartHelper::prepareData($orders)];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderById(): array
    {
        $order = $this->validateAndGetOrder(['customer', 'order_items']);

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getTotalPaidAmount(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'total_paid_amount' => $order->getTotalPaidAmount(),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getTotalRefundAmount(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'total_refund_amount' => $order->getTotalRefundAmount(),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getLatestTransaction(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = FluentCartHelper::prepareData($order->getLatestTransaction() ?? []);

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getCurrentSubscription(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = FluentCartHelper::prepareData($order->currentSubscription() ?? []);

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function generateReceiptNumber(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = FluentCartHelper::prepareData($order->generateReceiptNumber() ?? []);

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getReceiptUrl(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'receipt_url' => $order->getReceiptUrl(),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getParentOrder(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order->parentOrder ?? []),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getChildOrder(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order->children ?? []),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderTransactions(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'transactions' => FluentCartHelper::prepareData($order->transactions ?? []),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderSubscriptions(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'subscriptions' => FluentCartHelper::prepareData($order->subscriptions ?? []),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderItems(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'order_items' => FluentCartHelper::prepareData($order->order_items ?? []),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderCustomer(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order->customer ?? []),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderMetadata(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'metadata' => FluentCartHelper::prepareData($order->order_meta ?? []),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderMetadataByKey(): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $rules = [
            'id'       => ['required', 'integer'],
            'meta_key' => ['required', 'sanitize:text'],
        ];

        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        $order = Order::find($fieldMappings['id']);

        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        $metaValue = $order->getMeta($fieldMappings['meta_key']);

        if (!$metaValue) {
            return [
                'response'    => __('Metadata key not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        $data = [
            'meta_key'   => $fieldMappings['meta_key'],
            'meta_value' => $metaValue,
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function updateOrderMetadata(): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $rules = [
            'id'         => ['required', 'integer'],
            'meta_key'   => ['required', 'sanitize:text'],
            'meta_value' => ['required', 'sanitize:text'],
        ];

        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        $order = Order::find($fieldMappings['id']);

        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        $data = [
            'metadata' => $order->updateMeta(
                $fieldMappings['meta_key'],
                $fieldMappings['meta_value']
            ),
        ];


        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function deleteOrderMetadata(): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $rules = [
            'id'       => ['required', 'integer'],
            'meta_key' => ['required', 'sanitize:text'],
        ];

        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        $order = Order::find($fieldMappings['id']);

        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        if (!$order->deleteMeta($fieldMappings['meta_key'])) {
            return [
                'response'    => __('Failed to delete the metadata.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 500
            ];
        }

        return [
            'response'    => __('Metadata deleted successfully.', 'bit-pi'),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderCoupons(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'applied_coupons' => FluentCartHelper::prepareData($order->appliedCoupons ?? []),
            'used_coupons'    => FluentCartHelper::prepareData($order->usedCoupons ?? []),
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderShippingAddress(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order->shipping_address ?? []),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderBillingAddress(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        return [
            'response'    => FluentCartHelper::prepareData($order->billing_address ?? []),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderAddresses(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'order_addresses' => $order->order_addresses ?? [],
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderLicenses(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'licenses' => $order->licenses ?? [],
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderLabels(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'labels' => $order->labels ?? [],
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderRenewals(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'renewals' => $order->renewals ?? [],
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function getOrderTaxRates(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        $data = [
            'order_tax_rates' => $order->order_tax_rates ?? [],
        ];

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }

    public function updateOrderStatus(): array
    {
        return $this->validateAndUpdateOrderStatus('status');
    }

    public function updatePaymentStatus(): array
    {
        return $this->validateAndUpdateOrderStatus('payment_status');
    }

    public function updateShippingStatus(): array
    {
        return $this->validateAndUpdateOrderStatus('shipping_status');
    }

    public function createOrder(): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence(['order', 'order_item'])) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $fieldMappings['products_map'] = $this->nodeInfoProvider->getFieldMapRepeaters('product-map.value', false, false);

        $rules = ['customer_id' => ['required', 'integer']];
        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        if (isset($fieldMappings['note'])) {
            $fieldMappings['note'] = sanitize_textarea_field($fieldMappings['note']);
        }
        if (isset($fieldMappings['payment_method'])) {
            $fieldMappings['payment_method'] = sanitize_text_field($fieldMappings['payment_method']);
        }
        if (isset($fieldMappings['payment_method_title'])) {
            $fieldMappings['payment_method_title'] = sanitize_text_field($fieldMappings['payment_method_title']);
        }

        $order = Order::create($fieldMappings);
        if (!$order) {
            return [
                'response'    => __('Failed to create the order.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 500
            ];
        }

        foreach ($fieldMappings['products_map'] as $itemData) {
            if (empty($itemData['product_id']) || empty($itemData['quantity'])) {
                continue;
            }

            $productId = \intval($itemData['product_id']);
            $unitPrice = \floatval($itemData['unit_price'] ?? 0);
            $quantity = \intval($itemData['quantity']);

            if ($quantity <= 0) {
                continue;
            }

            $product = get_post($productId);
            if (!$product || $product->post_type !== 'fluent_products') {
                continue;
            }

            $productTitle = isset($product->post_title)
                ? sanitize_text_field($product->post_title)
                : 'Product';

            $subtotal = $unitPrice * $quantity;

            OrderItem::create(
                [
                    'order_id'   => $order->id,
                    'post_id'    => $productId,
                    'post_title' => $productTitle,
                    'title'      => $productTitle,
                    'quantity'   => $quantity,
                    'unit_price' => $unitPrice,
                    'subtotal'   => $subtotal,
                    'line_total' => $subtotal,
                ]
            );
        }

        $subtotal = OrderItem::where('order_id', $order->id)->sum('line_total');

        // Calculate total_amount: subtotal + shipping + tax - discounts.
        $total_amount = $subtotal
            + $order->shipping_total
            + $order->tax_total
            + $order->shipping_tax
            - $order->manual_discount_total
            - $order->coupon_discount_total;

        // Update order with calculated totals.
        $order->update(
            [
                'subtotal'     => $subtotal,
                'total_amount' => $total_amount,
            ]
        );

        $data = FluentCartHelper::prepareData($order->fresh());

        return [
            'response'    => $data,
            'payload'     => $fieldMappings,
            'status_code' => 201
        ];
    }

    public function updateOrder(): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = ['order_id' => ['required', 'integer']];
        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        $order = Order::find($fieldMappings['order_id']);
        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        $order->update($fieldMappings);

        $data = FluentCartHelper::prepareData($order->fresh());

        return [
            'response'    => $data,
            'payload'     => $fieldMappings,
            'status_code' => 201
        ];
    }

    public function deleteOrder(): array
    {
        $order = $this->validateAndGetOrder();

        if (!$order instanceof Order) {
            return $order;
        }

        if (!$order->delete()) {
            return [
                'response'    => __('Failed to delete the order.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 500
            ];
        }

        return [
            'response'    => __('Order deleted successfully.', 'bit-pi'),
            'payload'     => [],
            'status_code' => 200
        ];
    }

    /**
     * Validate and get order.
     */
    private function validateAndGetOrder(array $relations = []): array|Order
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $rules = ['id' => ['required', 'integer']];

        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        if (empty($relations)) {
            $order = Order::find($fieldMappings['id']);
        } else {
            $order = Order::with($relations)->find($fieldMappings['id']);
        }

        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        return $order;
    }

    /**
     * Validate and update order status.
     */
    private function validateAndUpdateOrderStatus(string $key): array
    {
        if ($validationError = FluentCartHelper::validateClassExistence('order')) {
            return $validationError;
        }

        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();
        $rules = [
            'id'     => ['required', 'integer'],
            'status' => ['required', 'sanitize:text'],
        ];

        if ($validationError = FluentCartHelper::validateFieldMap($fieldMappings, $rules)) {
            return $validationError;
        }

        $order = Order::find($fieldMappings['id']);

        if (!$order) {
            return [
                'response'    => __('Order not found.', 'bit-pi'),
                'payload'     => [],
                'status_code' => 404
            ];
        }

        $order->updateStatus($key, $fieldMappings['status']);

        $data = FluentCartHelper::prepareData($order->fresh());

        return [
            'response'    => $data,
            'payload'     => [],
            'status_code' => 200
        ];
    }
}
