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

namespace PortalPeople\palletways\controllers;

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

/**
 * ConsignmentController
 *
 * Handles consignment creation, cancellation, manifesting, tracking and
 * label retrieval via the Palletways 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'],
                    'delete'   => ['POST'],
                    'manifest' => ['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();

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            /** @var \PortalPeople\palletways\Module $module */
            $module    = Yii::$app->getModule('palletways');
            $confirm   = $module ? $module->autoConfirm : false;
            $uniqueRef = 'NGPW-' . date('YmdHis') . '-' . rand(1000, 9999);

            // Use queue if available, otherwise send synchronously
            if (Yii::$app->has('queue')) {
                Yii::$app->queue->push(new ConsignmentJob([
                    'manifest'  => $model->getManifest($confirm),
                    'uniqueRef' => $uniqueRef,
                    'commit'    => true,
                ]));

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

            // Synchronous send
            $result = $this->sendConsignment($model, $confirm);

            $statusCode = $result['Response']['Status']['Code'] ?? '';

            if ($statusCode === 'OK') {
                $responseId = $result['Response']['Detail']['ImportDetail']['ResponseID'] ?? '';
                $info       = $result['Response']['Detail']['ImportDetail']['Information'] ?? '';
                Yii::$app->session->setFlash('success', 'Consignment created (Ref: ' . $uniqueRef . '). Response ID: ' . $responseId . ($info ? ' | ' . $info : ''));
                return $this->refresh();
            }

            $description = $result['Response']['Status']['Description'] ?? 'unknown error';
            Yii::$app->session->setFlash('error', 'Palletways error: ' . $description);
        }

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

    /**
     * AJAX: delete a consignment from the customer account (before manifesting).
     *
     * Only works on consignments created with Confirm=no.
     *
     * @return array
     */
    public function actionDelete(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $client = Yii::$app->palletwaysClient;
            $result = $client->deleteConsignment($responseId);
            $code   = $result['Response']['Status']['Code'] ?? 'ERROR';
            return [
                'success' => $code === 'OK',
                'message' => $result['Response']['Status']['Description'] ?? '',
            ];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * AJAX: manifest (confirm and submit) a pending consignment to the depot.
     *
     * Only works on consignments created with Confirm=no.
     *
     * @return array
     */
    public function actionManifest(): array
    {
        Yii::$app->response->format = Response::FORMAT_JSON;

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

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

        try {
            $client = Yii::$app->palletwaysClient;
            $result = $client->manifestConsignment($responseId);
            $code   = $result['Response']['Status']['Code'] ?? 'ERROR';
            return [
                'success' => $code === 'OK',
                'message' => $result['Response']['Status']['Description'] ?? '',
            ];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

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

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

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

        try {
            $client = Yii::$app->palletwaysClient;
            $result = $client->getTrackingNotesByConNo($conNo);
            $code   = $result['Response']['Status']['Code'] ?? 'ERROR';
            return [
                'success' => $code === 'OK',
                'data'    => $result['Response']['Detail'] ?? $result,
            ];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * Retrieve and stream a consignment label PDF by Response ID.
     *
     * @return Response
     */
    public function actionLabels(): Response
    {
        $responseId = Yii::$app->request->get('responseId');
        $conNo      = Yii::$app->request->get('conNo');

        try {
            $client = Yii::$app->palletwaysClient;

            if (!empty($responseId)) {
                $pdf      = $client->getLabelsById($responseId);
                $filename = 'label-' . $responseId . '.pdf';
            } elseif (!empty($conNo)) {
                $pdf      = $client->getLabelsByConNo($conNo);
                $filename = 'label-' . $conNo . '.pdf';
            } else {
                Yii::$app->response->statusCode = 400;
                return $this->asJson(['success' => false, 'message' => 'responseId or conNo is required.']);
            }

            return Yii::$app->response->sendContentAsFile($pdf, $filename, [
                'mimeType' => 'application/pdf',
                'inline'   => true,
            ]);
        } catch (\Exception $e) {
            Yii::$app->response->statusCode = 500;
            return $this->asJson(['success' => false, 'message' => $e->getMessage()]);
        }
    }

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

        $type       = Yii::$app->request->get('type', 'D');
        $colCountry = Yii::$app->request->get('colCountry', 'GB');
        $colPost    = Yii::$app->request->get('colPostcode', '');
        $delCountry = Yii::$app->request->get('delCountry', 'GB');
        $delPost    = Yii::$app->request->get('delPostcode', '');

        if (empty($colPost) || empty($delPost)) {
            return ['success' => false, 'message' => 'colPostcode and delPostcode are required.'];
        }

        try {
            $client = Yii::$app->palletwaysClient;
            $result = $client->getAvailableServices($type, $colCountry, $colPost, $delCountry, $delPost);
            $code   = $result['Response']['Status']['Code'] ?? 'ERROR';
            return [
                'success' => $code === 'OK',
                'data'    => $result['Response']['Detail'] ?? $result,
            ];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

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

    /**
     * Send a consignment synchronously and return the API response.
     *
     * @param ConsignmentForm $model
     * @param bool            $confirm
     * @return array
     */
    private function sendConsignment(ConsignmentForm $model, bool $confirm): array
    {
        try {
            $client = Yii::$app->palletwaysClient;
            return $client->createConsignment($model->getManifest($confirm), true);
        } catch (\Exception $e) {
            Yii::error('Palletways consignment error: ' . $e->getMessage(), 'palletways');
            return [
                'Response' => [
                    'Status' => ['Code' => 'ERROR', 'Description' => $e->getMessage()],
                ],
            ];
        }
    }
}
