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

namespace PortalPeople\dx\controllers;

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

/**
 * ConsignmentController
 *
 * Handles consignment creation, cancellation, tracking and labels via the
 * DX Despatch Manager 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'],
                    'cancel' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Form to create a new 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\dx\Module $module */
        $module = Yii::$app->getModule('dx');

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

            // 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 {
                $client = Yii::$app->dxClient;
                $result = $client->createConsignment($consignmentData);
                $tracking = implode(', ', $result['trackingNumbers'] ?? []);
                Yii::$app->session->setFlash('success', 'Consignment created. Tracking: ' . $tracking);
                return $this->refresh();
            } catch (\Exception $e) {
                Yii::$app->session->setFlash('error', 'DX error: ' . $e->getMessage());
            }
        }

        // Populate available services for the service code dropdown
        $services = [];
        try {
            if ($module && $module->isConfigured() && !empty($model->postcode)) {
                $services = Yii::$app->dxClient->getServices($model->postcode) ?? [];
            }
        } catch (\Exception $e) {
            // silently ignore – services dropdown will be empty
        }

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

    /**
     * AJAX: cancel an individual item (must be done before despatch date).
     *
     * @return array
     */
    public function actionCancel(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $result = Yii::$app->dxClient->cancelItem($trackingNumber);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: get tracking events for a consignment.
     *
     * @return array
     */
    public function actionTracking(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $result = Yii::$app->dxClient->trackingGetConsignment($trackingNumber);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: get available services for a delivery postcode.
     *
     * @return array
     */
    public function actionServices(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $postcode    = Yii::$app->request->get('postcode');
        $countryCode = Yii::$app->request->get('countryCode', 'GB');

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

        try {
            $result = Yii::$app->dxClient->getServices($postcode, $countryCode);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: retrieve a PDF label (Base64-encoded).
     *
     * @return array
     */
    public function actionLabelPdf(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $result = Yii::$app->dxClient->printLabelPdf($trackingNumber);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: retrieve a ZPL label.
     *
     * @return array
     */
    public function actionLabelZpl(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $result = Yii::$app->dxClient->printLabelZpl($trackingNumber);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
}
