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

namespace PortalPeople\palletforce\models;

use yii\base\Model;

/**
 * ConsignmentForm
 *
 * Validates and builds the payload for a single Palletforce consignment.
 * Maps cleanly to the UploadManifest API request body structure.
 *
 * Service codes:   A=24hr, B=48hr, C=72hr, D=3-5 days
 * Pallet types:    F=Full, H=Half, Q=Quarter, O=Oversize
 * Insurance codes: 05 (standard) – confirm with Palletforce
 */
class ConsignmentForm extends Model
{
    // -------------------------------------------------------------------------
    // Collection address
    // -------------------------------------------------------------------------
    public $collectionName;
    public $collectionStreet;
    public $collectionLocation;
    public $collectionTown;
    public $collectionCounty;
    public $collectionPostcode;
    public $collectionCountryCode = 'GB';
    public $collectionPhone;
    public $collectionContact;

    // -------------------------------------------------------------------------
    // Delivery address
    // -------------------------------------------------------------------------
    public $deliveryName;
    public $deliveryStreet;
    public $deliveryLocation;
    public $deliveryTown;
    public $deliveryCounty;
    public $deliveryPostcode;
    public $deliveryCountryCode = 'GB';
    public $deliveryPhone;
    public $deliveryContact;

    // -------------------------------------------------------------------------
    // Consignment details
    // -------------------------------------------------------------------------

    /** @var string Collection date YYYYMMDD – mandatory. */
    public $collectionDate;

    /** @var string Service code: A, B, C, D. */
    public $serviceName = 'A';

    /** @var string Pallet type: F, H, Q, O. */
    public $palletType = 'H';

    /** @var int Number of pallets. */
    public $numberOfPallets = 1;

    /** @var int Total pallet spaces (including oversize extras). */
    public $palletSpaces = 1;

    /** @var float|int Gross weight in kg (rounded up to nearest kg). */
    public $weight;

    /** @var string Surcharge codes, space-separated (e.g. 'TL AM'). */
    public $surcharges;

    /** @var string Customer's own order/reference. */
    public $customerReference;

    /** @var string Second customer reference. */
    public $customerReference2;

    /** @var string Free-text notes (appears on label as NOTE1). */
    public $notes;

    /** @var string Insurance code (default 05). */
    public $insuranceCode = '05';

    /** @var string Consignment type: 0=Standard, 1=Reverse, 2=3-way. */
    public $consignmentType = '0';

    /** @var string Notification email address for delivery updates. */
    public $notificationEmail;

    /** @var string Notification SMS number. */
    public $notificationSms;

    /** @var string acceptedStatus: Y=immediately accepted, N=pending accept step. */
    public $acceptedStatus = 'Y';

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

    /** @inheritdoc */
    public function rules(): array
    {
        return [
            // Collection address
            [['collectionName', 'collectionStreet', 'collectionTown', 'collectionPostcode', 'collectionPhone', 'collectionContact'], 'required'],
            [['collectionName', 'collectionContact'], 'string', 'max' => 30],
            [['collectionStreet', 'collectionLocation', 'collectionTown', 'collectionCounty'], 'string', 'max' => 30],
            [['collectionPostcode'], 'string', 'max' => 10],
            [['collectionCountryCode'], 'string', 'max' => 2],
            [['collectionPhone'], 'string', 'max' => 16],

            // Delivery address
            [['deliveryName', 'deliveryStreet', 'deliveryTown', 'deliveryPostcode', 'deliveryPhone', 'deliveryContact'], 'required'],
            [['deliveryName', 'deliveryContact'], 'string', 'max' => 30],
            [['deliveryStreet', 'deliveryLocation', 'deliveryTown', 'deliveryCounty'], 'string', 'max' => 30],
            [['deliveryPostcode'], 'string', 'max' => 10],
            [['deliveryCountryCode'], 'string', 'max' => 2],
            [['deliveryPhone'], 'string', 'max' => 16],

            // Consignment
            [['collectionDate', 'serviceName', 'palletType', 'numberOfPallets', 'palletSpaces', 'weight', 'insuranceCode'], 'required'],
            [['collectionDate'], 'match', 'pattern' => '/^\d{8}$/', 'message' => 'Collection date must be in YYYYMMDD format.'],
            [['serviceName'], 'in', 'range' => ['A', 'B', 'C', 'D']],
            [['palletType'], 'in', 'range' => ['F', 'H', 'Q', 'O']],
            [['numberOfPallets', 'palletSpaces'], 'integer', 'min' => 1],
            [['weight'], 'number', 'min' => 0.1],
            [['acceptedStatus'], 'in', 'range' => ['Y', 'N']],
            [['consignmentType'], 'in', 'range' => ['0', '1', '2']],
            [['surcharges', 'customerReference', 'customerReference2', 'notes', 'notificationEmail', 'notificationSms', 'insuranceCode'], 'string'],
            [['notificationEmail'], 'email'],
            [['collectionLocation', 'collectionCounty', 'deliveryLocation', 'deliveryCounty', 'surcharges', 'customerReference', 'customerReference2', 'notes', 'notificationEmail', 'notificationSms'], 'default', 'value' => ''],
        ];
    }

    /** @inheritdoc */
    public function attributeLabels(): array
    {
        return [
            'collectionName'        => 'Collection Company Name',
            'collectionStreet'      => 'Collection Street Address',
            'collectionLocation'    => 'Collection Location/Address 2',
            'collectionTown'        => 'Collection Town',
            'collectionCounty'      => 'Collection County',
            'collectionPostcode'    => 'Collection Postcode',
            'collectionCountryCode' => 'Collection Country',
            'collectionPhone'       => 'Collection Phone',
            'collectionContact'     => 'Collection Contact Name',
            'deliveryName'          => 'Delivery Company Name',
            'deliveryStreet'        => 'Delivery Street Address',
            'deliveryLocation'      => 'Delivery Location/Address 2',
            'deliveryTown'          => 'Delivery Town',
            'deliveryCounty'        => 'Delivery County',
            'deliveryPostcode'      => 'Delivery Postcode',
            'deliveryCountryCode'   => 'Delivery Country',
            'deliveryPhone'         => 'Delivery Phone',
            'deliveryContact'       => 'Delivery Contact Name',
            'collectionDate'        => 'Collection Date',
            'serviceName'           => 'Service Level',
            'palletType'            => 'Pallet Type',
            'numberOfPallets'       => 'Number of Pallets',
            'palletSpaces'          => 'Pallet Spaces',
            'weight'                => 'Weight (kg)',
            'surcharges'            => 'Surcharges',
            'customerReference'     => 'Customer Reference 1',
            'customerReference2'    => 'Customer Reference 2',
            'notes'                 => 'Delivery Notes',
            'insuranceCode'         => 'Insurance Code',
            'consignmentType'       => 'Consignment Type',
            'notificationEmail'     => 'Notification Email',
            'notificationSms'       => 'Notification SMS',
            'acceptedStatus'        => 'Accept Immediately',
        ];
    }

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

    /**
     * Build the collection address array for the API.
     * @return array
     */
    public function getCollectionAddress(): array
    {
        return [
            'name'          => $this->collectionName,
            'streetAddress' => $this->collectionStreet,
            'location'      => $this->collectionLocation,
            'town'          => $this->collectionTown,
            'county'        => $this->collectionCounty,
            'postcode'      => $this->collectionPostcode,
            'countryCode'   => $this->collectionCountryCode ?: 'GB',
            'phoneNumber'   => $this->collectionPhone,
            'contactName'   => $this->collectionContact,
        ];
    }

    /**
     * Build the delivery address array for the API.
     * @return array
     */
    public function getDeliveryAddress(): array
    {
        return [
            'name'          => $this->deliveryName,
            'streetAddress' => $this->deliveryStreet,
            'location'      => $this->deliveryLocation,
            'town'          => $this->deliveryTown,
            'county'        => $this->deliveryCounty,
            'postcode'      => $this->deliveryPostcode,
            'countryCode'   => $this->deliveryCountryCode ?: 'GB',
            'phoneNumber'   => $this->deliveryPhone,
            'contactName'   => $this->deliveryContact,
        ];
    }

    /**
     * Build the consignment array for the API.
     *
     * Tracking number and collecting/delivery depot are left blank so
     * Palletforce Alliance assigns them automatically.
     *
     * @return array
     */
    public function getConsignmentData(): array
    {
        $consignment = [
            'requestingDepot'          => '',   // injected by PalletforceClient
            'collectingDepot'          => '',   // assigned by Alliance
            'deliveryDepot'            => '',   // assigned by Alliance
            'trackingNumber'           => '',   // assigned by Alliance
            'consignmentNumber'        => '',
            'CustomerAccountNumber'    => '',   // injected by PalletforceClient
            'datesAndTimes'            => [
                ['dateTimeType' => 'COLD', 'value' => $this->collectionDate],
            ],
            'pallets'                  => [
                ['palletType' => $this->palletType, 'numberofPallets' => (string) $this->numberOfPallets],
            ],
            'palletSpaces'             => (string) $this->palletSpaces,
            'weight'                   => (string) (int) ceil((float) $this->weight),
            'serviceName'              => $this->serviceName,
            'surcharges'               => $this->surcharges,
            'customersUniqueReference' => $this->customerReference,
            'customersUniqueReference2'=> $this->customerReference2,
            'notes'                    => [],
            'insuranceCode'            => $this->insuranceCode,
            'customerCharge'           => '',
            'nonPalletforceConsignment'=> '',
            'deliveryVehicleCode'      => '',
            'consignmentType'          => $this->consignmentType,
            'hubIdentifyingCode'       => '',
            'notifications'            => [],
            'cartonCount'              => '',
            'acceptedStatus'           => $this->acceptedStatus,
        ];

        // Notes
        if (!empty($this->notes)) {
            $consignment['notes'][] = ['noteName' => 'NOTE1', 'value' => $this->notes];
        }

        // Notifications
        if (!empty($this->notificationEmail)) {
            $consignment['notifications'][] = ['notificationType' => 'EMAIL', 'value' => $this->notificationEmail];
        }
        if (!empty($this->notificationSms)) {
            $consignment['notifications'][] = ['notificationType' => 'SMS', 'value' => $this->notificationSms];
        }

        return $consignment;
    }
}
