<?php
namespace PortalPeople\gforce\services;

use Yii;
use backend\models\ActionLog;

class NewConsignment
{
    private $data;
    private $cart;

    public function __construct($data = [], $cart = null)
    {
        $this->data = $data;
        $this->cart = $cart;
    }

    /**
     * Create a consignment. Returns array on success, false on failure.
     * Avoids using session flashes when running in console.
     */
    public function create()
    {
        $module = Yii::$app->getModule('gforce');
        $model = new \PortalPeople\gforce\models\ConsignmentForm();
        /** @var \PortalPeople\gforce\components\ConsignmentService $consignmentService */
        $consignmentService = Yii::createObject(\PortalPeople\gforce\components\ConsignmentService::class);

        // allow consignment service to populate model from cart if provided
        if ($this->cart !== null) {
            $consignmentService->prepopulateModelFromCart($model, $module, $this->cart);
        }

        $confirm   = $module && isset($module->autoConfirm) ? $module->autoConfirm : false;
        $uniqueRef = $consignmentService->buildUniqueRef();
        $manifest  = $model->getManifest($confirm);

        try {
            // validate route/preflight (may return ['ok' => true/false])
            $preflight = $consignmentService->validateRouteAndPreflight($model, $module, $manifest);
            Yii::warning(['preflight_errors' => $preflight, 'manifest' => $manifest], 'gforce');
            if (array_key_exists('Errors', $preflight) && count($preflight['Errors']) > 0) {
                $msg = $preflight['message'] ?? 'No delivery route available';
                $this->maybeFlash('error', 'gforce preflight failed: ' . $msg);
                return false;
            }
            Yii::warning(['preflight_success' => $preflight], 'gforce.trydone' );
        } catch (\Exception $e) {
            Yii::error('gforce error: ' . $e->getMessage(), 'gforce');
            return false;
        }

        // Defensive manifest validation before sending to provider
        $errors = [];
        // References
        if (!isset($manifest['References']['ConsignmentType'])) {
            $errors[] = 'References.ConsignmentType is required';
        } else {
            // ensure it's a string as in provider example
            $manifest['References']['ConsignmentType'] = (string) $manifest['References']['ConsignmentType'];
        }

        // Collection/Delivery addresses
        if (empty($manifest['Collection']['Address']['Postcode'] ?? '')) {
            $errors[] = 'Delivery postcode is required';
        }
        if (empty($manifest['Delivery']['Address']['Name'] ?? '') && empty($manifest['Delivery']['Contacts'][0]['Name'] ?? '')) {
            $errors[] = 'Delivery contact name is required';
        }
        $totalSpaces = (int) ($manifest['GoodsDefinition']['TotalSpaces'] ?? 0);
        $hasItems = !empty($manifest['GoodsDefinition']['Items']);
        if ($totalSpaces <= 0 && !$hasItems) {
            $errors[] = 'No goods definition items or total spaces specified';
        }
        // Validate item types
        $allowedItemTypes = ['FULL', 'OVERSIZE', 'QUARTER', 'HALF', 'THIRD'];
        if ($hasItems) {
            foreach ($manifest['GoodsDefinition']['Items'] as $i => $item) {
                $it = strtoupper((string) ($item['ItemType'] ?? ''));
                if ($it === '') {
                    $errors[] = "GoodsDefinition.Items[$i].ItemType is required";
                    continue;
                }
                if (!in_array($it, $allowedItemTypes, true)) {
                    $errors[] = "GoodsDefinition.Items[$i].ItemType '$it' is not allowed";
                }
            }
        }
        if (count($errors) > 0) {
            Yii::error(['manifest_validation_errors' => $errors, 'manifest' => $manifest], 'gforce');
            return false;
        }
        $cart = $this->cart;
                // perform the create request once
        ActionLog::create(['class' => self::class, 'action' => 'create', 'relatedid' => $cart->id, 'type' => 'Info', 'message' => "gforce consignment creation attempt for cart"]);
            
        $result = $preflight;
        $consignmentService->persistCartConsignmentResult($cart, $result['ConsignmentNumber']);
        $client = Yii::$app->gforceClient;
        $pdf = $client->getLabelsById($result['TrackingCode']);
        if ($result['TrackingCode']) {
            ActionLog::create(['class' => self::class, 'action' => 'create', 'relatedid' => $cart->id, 'type' => 'Info', 'message' => "gforce consignment created for cart (Consignment: {$result['TrackingCode']})"]);
        }
        //Yii::$app->trigger('cart-dispatched-'.$cart->account_code, new \common\events\UserDataEvent(['model' => $cart, 'customData' => ['new' => true]]));
        //       Yii::$app->trigger('cart-dispatch-email-'.$cart->account_code, new \common\events\UserDataEvent(['model' => $cart, 'customData' => ['new' => true]]));
        //Yii::$app->trigger('netsuite.dispatched', new \common\events\UserDataEvent(['model' => $cart, 'customData' => ['Dispatched']]));
        return [
            [
                'trackingInfo' => 'gforce Consignment ID: ' . $result['ConsignmentNumber'],
                'trackingNumbers' => $result['TrackingCode'],
                'data' => base64_encode($pdf),
            ]
        ];
        $description = $consignmentService->getStatusDescription($result, 'unknown error');
        if (!empty($result['ValidationErrors'])) {
            $description .= ' Validation: ' . json_encode($result['ValidationErrors'], JSON_UNESCAPED_SLASHES);
        }
        $this->maybeFlash('error', 'gforce error: ' . $description);
        return false;
    }

    private function maybeFlash($key, $message)
    {
        if (Yii::$app->has('session') && PHP_SAPI !== 'cli') {
            Yii::$app->session->setFlash($key, $message);
        } else {
            Yii::warning($message, 'gforce');
        }
    }
}