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

namespace PortalPeople\palletforce\controllers;

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

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

    /**
     * Form to create a new consignment.
     *
     * Accepts an optional `id` GET parameter to pre-populate delivery address,
     * weight and reference from an existing cart.
     *
     * On POST: validates, then queues (if submitAction=queue and queue is
     * available) or sends directly to Palletforce. On success, tracking data
     * is written back to the cart when an id was provided.
     *
     * @return string|Response
     */
    public function actionCreate()
    {
        $model = new ConsignmentForm();
        $id    = Yii::$app->request->get('id', null);
        $cart  = $id !== null ? Cartsbe::findOne(['id' => $id]) : null;

        if ($cart !== null && Yii::$app->request->isGet) {
            $shippingAddress = $cart->fulladdresses['shipping'] ?? null;
            if ($shippingAddress) {
                $country     = strtoupper((string) ($shippingAddress->country ?? ''));
                $countryCode = strlen($country) === 2 ? $country : 'GB';

                $model->deliveryName        = (string) ($shippingAddress->company_name ?? $shippingAddress->companyname ?? '');
                $model->deliveryContact     = (string) ($cart->contact ?? trim($shippingAddress->firstname . ' ' . $shippingAddress->lastname));
                $model->deliveryStreet      = (string) ($shippingAddress->address1 ?? '');
                $model->deliveryLocation    = (string) ($shippingAddress->address2 ?? '');
                $model->deliveryTown        = (string) ($shippingAddress->town ?? '');
                $model->deliveryCounty      = (string) ($shippingAddress->county ?? '');
                $model->deliveryPostcode    = (string) ($shippingAddress->postcode ?? '');
                $model->deliveryCountryCode = $countryCode;
                $model->deliveryPhone       = (string) ($shippingAddress->telephone ?? '');
                $model->notificationEmail   = (string) ($shippingAddress->email ?? $cart->email ?? '');
            }

            $deliveryLines  = $cart->deliveryCartlines;
            $lineWeight     = is_array($deliveryLines)
                ? (float) array_sum(array_column($deliveryLines, 'totalweight'))
                : 0.0;
            $fallbackWeight = (float) ($cart->totalweight ?? 0);

            if ($lineWeight > 0) {
                $model->weight = (int) ceil($lineWeight / 1000); // grams → kg
            } elseif ($fallbackWeight > 0) {
                $model->weight = (int) ceil($fallbackWeight / 1000);
            }

            $model->customerReference = (string) $cart->porderref;
            $model->collectionDate    = date('Ymd');
        }

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            $uniqueRef    = 'NGPF-' . date('YmdHis') . '-' . rand(1000, 9999);
            $submitAction = Yii::$app->request->post('submitAction');

            // Queue only when explicitly requested and a queue component exists
            if (Yii::$app->has('queue') && $submitAction === 'queue') {
                Yii::$app->queue->push(new ConsignmentJob([
                    'consignmentData'   => $model->getConsignmentData(),
                    'collectionAddress' => $model->getCollectionAddress(),
                    'deliveryAddress'   => $model->getDeliveryAddress(),
                    'uniqueRef'         => $uniqueRef,
                ]));

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

            // Direct send (default)
            try {
                $client = Yii::$app->palletforceClient;
                $result = $client->uploadManifest(
                    $model->getConsignmentData(),
                    $uniqueRef,
                    $model->getCollectionAddress(),
                    $model->getDeliveryAddress()
                );

                if ($result['success'] ?? $result['Success'] ?? false) {
                    $codes    = $result['trackingCodes'] ?? $result['TrackingCodes'] ?? [];
                    $tracking = implode(', ', $codes);

                    if ($cart !== null) {
                        $cart->data->palletforce->tracking_number = $tracking;
                        $cart->data->palletforce->status          = 'Consignment Created';
                        $cart->data->palletforce->despatch_date   = date('Y-m-d H:i:s');
                        $cart->save();
                    }

                    Yii::$app->session->setFlash('success', 'Consignment created. Tracking: ' . $tracking);
                    return $this->refresh();
                }

                Yii::$app->session->setFlash('error', 'Palletforce error: ' . ($result['message'] ?? $result['Message'] ?? 'unknown error'));
            } catch (\Exception $e) {
                Yii::$app->session->setFlash('error', 'Palletforce error: ' . $e->getMessage());
            }
        }

        return $this->render('create', [
            'model'          => $model,
            'queueAvailable' => Yii::$app->has('queue'),
        ]);
    }

    /**
     * AJAX: cancel (delete) a consignment before acceptance.
     *
     * @return array
     */
    public function actionCancel(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $trackingCode = Yii::$app->request->post('trackingCode');
        $uniqueRef    = 'NGPF-DEL-' . date('YmdHis');

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

        try {
            $client = Yii::$app->palletforceClient;
            $result = $client->deleteConsignment($trackingCode, $uniqueRef);
            return ['success' => $result['success'] ?? $result['Success'] ?? false, 'message' => $result['message'] ?? $result['Message'] ?? ''];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: accept one or more pending consignments.
     *
     * @return array
     */
    public function actionAccept(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $trackingCodes = (array) Yii::$app->request->post('trackingCodes', []);
        $uniqueRef     = 'NGPF-ACC-' . date('YmdHis');

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

        try {
            $client = Yii::$app->palletforceClient;
            $result = $client->acceptConsignments($trackingCodes, $uniqueRef);
            return ['success' => $result['success'] ?? $result['Success'] ?? false, 'message' => $result['message'] ?? $result['Message'] ?? ''];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

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

        $trackingNumber = Yii::$app->request->get('trackingNumber');
        $uniqueRef      = 'NGPF-TRK-' . date('YmdHis');

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

        try {
            $client = Yii::$app->palletforceClient;
            $result = $client->downloadTrackingData($trackingNumber, $uniqueRef, [
                'lastUpdated' => '19700101000000',
            ]);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: get ETA for one or more consignments.
     *
     * @return array
     */
    public function actionEta(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $trackingCodes = (array) Yii::$app->request->get('trackingCodes', []);
        $uniqueRef     = 'NGPF-ETA-' . date('YmdHis');

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

        try {
            $client = Yii::$app->palletforceClient;
            $result = $client->downloadETATimes($trackingCodes, $uniqueRef);
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: print / retrieve labels (base64 images) for a consignment.
     *
     * @return array
     */
    public function actionLabels(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

        $trackingNumber = Yii::$app->request->get('trackingNumber');
        $palletNumber   = Yii::$app->request->get('palletNumber');
        $uniqueRef      = 'NGPF-LBL-' . date('YmdHis');

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

        try {
            $client = Yii::$app->palletforceClient;
            $result = $client->printLabels(
                $trackingNumber,
                $uniqueRef,
                $palletNumber !== null ? (int) $palletNumber : null
            );
            return ['success' => true, 'data' => $result];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    // -------------------------------------------------------------------------

    /**
     * Send a consignment synchronously and return the API response.
     *
     * @param ConsignmentForm $model
     * @param string          $uniqueRef
     * @return array
     */
    private function sendConsignment(ConsignmentForm $model, string $uniqueRef): array
    {
        try {
            $client = Yii::$app->palletforceClient;
            return $client->uploadManifest(
                $model->getConsignmentData(),
                $uniqueRef,
                $model->getCollectionAddress(),
                $model->getDeliveryAddress()
            );
        } catch (\Exception $e) {
            Yii::error('Palletforce consignment error: ' . $e->getMessage(), 'palletforce');
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }
}
