<?php
/**
 * Consignment Controller – UPN Delivery Module
 *
 * @category    PortalPeople
 * @package     UPN
 * @author      Portal People Development Team
 * @copyright   Copyright (c) 2026 Portal People (https://portalpeople.co.uk)
 */

namespace PortalPeople\upn\controllers;

use Yii;
use yii\web\Controller;
use yii\web\Response;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use PortalPeople\upn\models\ConsignmentForm;
use PortalPeople\upn\jobs\ConsignmentJob;

/**
 * ConsignmentController
 *
 * Handles pallet consignment creation, deletion, tracking and labels
 * via the UPN External Links SOAP API.
 */
class ConsignmentController extends Controller
{
    /** @inheritdoc */
    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
            'verbs' => [
                'class'   => VerbFilter::class,
                'actions' => [
                    'create' => ['POST', 'GET'],
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Form to create a new pallet consignment.
     *
     * On POST: validates, then dispatches a ConsignmentJob or sends directly
     * depending on whether a queue is available.
     *
     * @return string|Response
     */
    public function actionCreate()
    {
        $model = new ConsignmentForm();

        /** @var \PortalPeople\upn\Module $module */
        $module = Yii::$app->getModule('upn');

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            $customerId      = $module ? (int) $module->customerId : 0;
            $consignmentData = $model->getConsignmentData($customerId);

            // Use queue if available, otherwise send synchronously
            if (Yii::$app->has('queue')) {
                Yii::$app->queue->push(new ConsignmentJob([
                    'consignmentData' => $consignmentData,
                ]));

                Yii::$app->session->setFlash('success', 'Consignment queued for dispatch.');
                return $this->refresh();
            }

            // Synchronous send
            try {
                /** @var \PortalPeople\upn\components\UpnClient $client */
                $client     = Yii::$app->upnClient;
                $result     = $client->addConsignment($consignmentData);
                $conBarcode = is_object($result)
                    ? ($result->AddConsignment_V4Result ?? ($result->ConBarcode ?? ''))
                    : (is_array($result) ? ($result['ConBarcode'] ?? '') : '');

                $msg = 'Consignment created successfully.';
                if ($conBarcode) {
                    $msg .= ' Barcode: ' . $conBarcode;
                }
                Yii::$app->session->setFlash('success', $msg);
                return $this->refresh();
            } catch (\Exception $e) {
                Yii::$app->session->setFlash('error', 'UPN error: ' . $e->getMessage());
            }
        }

        return $this->render('create', ['model' => $model]);
    }

    /**
     * AJAX: delete an unprocessed consignment by barcode.
     *
     * Can only be called before UPN processes the consignment.
     *
     * @return array
     */
    public function actionDelete(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $conBarcode = Yii::$app->request->post('conBarcode');

        if (empty($conBarcode)) {
            return ['success' => false, 'message' => 'conBarcode is required.'];
        }

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client = Yii::$app->upnClient;
            $result = $client->deleteConsignment($conBarcode);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: retrieve pod and tracking events for the depot (all since last call).
     *
     * @return array
     */
    public function actionTracking(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client = Yii::$app->upnClient;
            $result = $client->getPodAndTrackingByDepot();
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: get status of one or more collection barcodes.
     *
     * POST body: barcodes[] array
     *
     * @return array
     */
    public function actionCollectionStatus(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $barcodes = Yii::$app->request->post('barcodes', []);

        if (empty($barcodes)) {
            return ['success' => false, 'message' => 'At least one barcode is required.'];
        }

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client = Yii::$app->upnClient;
            $result = $client->getCollectionStatus((array) $barcodes);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: get postcode restrictions / available services for a postcode district.
     *
     * GET param: postcode (e.g. "SW1A")
     *
     * @return array
     */
    public function actionServices(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $postcode = trim((string) Yii::$app->request->get('postcode', ''));

        if (empty($postcode)) {
            return ['success' => false, 'message' => 'postcode is required.'];
        }

        // Extract district only (e.g. "SW1A 1AA" → "SW1A")
        $district = strtoupper(explode(' ', $postcode)[0]);

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client = Yii::$app->upnClient;
            $result = $client->getPostcodeRestrictions($district);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: retrieve PDF pallet labels as a Base64-encoded string.
     *
     * GET param: conBarcode
     *
     * @return array
     */
    public function actionLabelPdf(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $conBarcode = Yii::$app->request->get('conBarcode');

        if (empty($conBarcode)) {
            return ['success' => false, 'message' => 'conBarcode is required.'];
        }

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client     = Yii::$app->upnClient;
            $labelData  = $client->getPalletLabelsAsString($conBarcode);
            return ['success' => true, 'data' => $labelData];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: retrieve run and expected delivery time for consignment barcodes.
     *
     * GET param: barcodes[] or conNumbers[]
     *
     * @return array
     */
    public function actionDeliveryTime(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $barcodes   = (array) Yii::$app->request->get('barcodes', []);
        $conNumbers = (array) Yii::$app->request->get('conNumbers', []);

        if (empty($barcodes) && empty($conNumbers)) {
            return ['success' => false, 'message' => 'barcodes or conNumbers is required.'];
        }

        try {
            /** @var \PortalPeople\upn\components\UpnClient $client */
            $client = Yii::$app->upnClient;
            $result = $client->getRunAndDeliveryTime($barcodes, $conNumbers);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
}
