<?php

namespace PortalPeople\virtualstock\services;

use yii\base\BaseObject;
use PortalPeople\virtualstock\components\VirtualStockClient;
use PortalPeople\virtualstock\constants\ApiEndpoints;
use PortalPeople\virtualstock\models\Order;

class OrderService extends BaseObject
{
    public VirtualStockClient $client;

    /**
     * List orders with optional filters.
     *
     * @param array{
     *   supplier_id?: string,
     *   retailer_id?: string,
     *   order_reference?: string,
     *   part_number?: string,
     *   status?: string,
     *   limit?: int,
     *   offset?: int
     * } $filters
     * @return array{results: Order[], count: int, next: string|null, previous: string|null}
     */
    public function listOrders(array $filters = []): array
    {
        $query = array_filter($filters, fn($v) => $v !== null && $v !== '');
        $query['format'] = 'json';

        $response = $this->client->request('GET', ApiEndpoints::ORDERS, $query);

        $orders = [];
        foreach ($response['results'] ?? [] as $item) {
            $orders[] = Order::fromArray($item);
        }

        return [
            'results'  => $orders,
            'count'    => (int) ($response['count'] ?? count($orders)),
            'next'     => $response['next'] ?? null,
            'previous' => $response['previous'] ?? null,
        ];
    }

    /**
     * Retrieve a single order by its ID/URI.
     */
    public function getOrder(string $orderId): Order
    {
        $path = ApiEndpoints::resolve(ApiEndpoints::ORDER, $orderId);
        $response = $this->client->request('GET', $path, ['format' => 'json']);
        return Order::fromArray($response);
    }

    /**
     * Acknowledge an order and provide expected dispatch/delivery dates per line.
     *
     * Each item in $lines must contain:
     *   - part_number (string)
     *   - line_ref (string)
     *   - quantity (int)
     *   - sub_status ('Pending' or 'Booked' — Screwfix requires 'Booked')
     *   - supplier_dispatch_date (ISO 8601 datetime string)
     *   - supplier_delivery_date (ISO 8601 datetime string)
     *
     * @param array<int, array<string, mixed>> $lines
     */
    public function acknowledgeOrder(string $orderId, array $lines): array
    {
        $path = ApiEndpoints::resolve(ApiEndpoints::ORDER_ACKNOWLEDGE, $orderId);
        return $this->client->request('POST', $path, ['items' => $lines]);
    }

    /**
     * Mark an order as dispatched.
     *
     * @param array<string, mixed> $payload
     */
    public function dispatchOrder(string $orderId, array $payload = []): array
    {
        $path = ApiEndpoints::resolve(ApiEndpoints::ORDER_DISPATCH, $orderId);
        return $this->client->request('POST', $path, $payload);
    }

    /**
     * Acknowledge a cancellation request.
     */
    public function cancelOrder(string $orderId, array $payload = []): array
    {
        $path = ApiEndpoints::resolve(ApiEndpoints::ORDER_CANCEL, $orderId);
        return $this->client->request('POST', $path, $payload);
    }

    /**
     * Paginate through all orders matching $filters, yielding Order objects.
     * Calls listOrders() repeatedly until there is no 'next' page.
     *
     * @return \Generator<Order>
     */
    public function iterateOrders(array $filters = []): \Generator
    {
        $filters['offset'] = $filters['offset'] ?? 0;
        $filters['limit']  = $filters['limit'] ?? 100;

        do {
            $page = $this->listOrders($filters);
            foreach ($page['results'] as $order) {
                yield $order;
            }
            $hasNext = $page['next'] !== null;
            $filters['offset'] += $filters['limit'];
        } while ($hasNext);
    }
}
