<?php

/**
 * This file contains QUI\ERP\Shipping\ShippingStatus\Handler
 */

namespace QUI\ERP\Shipping\ShippingStatus;

use QUI;
use QUI\ERP\Order\AbstractOrder;
use QUI\Permissions\Permission;

use function is_array;

/**
 * Class Handler
 * - Shipping status management
 * - Returns shipping status objects
 * - Returns shipping status lists
 *
 * @package QUI\ERP\Shipping\ShippingStatus\Factory
 */
class Handler extends QUI\Utils\Singleton
{
    /**
     * @var array<int, string>|null
     */
    protected ?array $list = null;

    /**
     * Exists a specific status?
     *
     * @param integer $id
     * @return bool
     */
    public function exists(int $id): bool
    {
        $list = Handler::getInstance()->getList();

        return isset($list[$id]);
    }

    /**
     * Return all shipping status entries from the config
     *
     * @return array<int, string>
     */
    public function getList(): array
    {
        if ($this->list !== null) {
            return $this->list;
        }

        try {
            $Package = QUI::getPackage('quiqqer/shipping');
            $Config = $Package->getConfig();

            if ($Config === null) {
                throw new QUI\Exception('Missing quiqqer/shipping config');
            }

            $result = $Config->getSection('shipping_status');
        } catch (QUI\Exception $Exception) {
            QUI\System\Log::writeException($Exception);

            return [];
        }

        if (!$result || !is_array($result)) {
            $this->list = [];

            return $this->list;
        }

        $this->list = $result;

        return $result;
    }

    /**
     * Refresh the internal list
     *
     * @return array<int, string>
     */
    public function refreshList(): array
    {
        $this->list = null;

        return $this->getList();
    }

    /**
     * Return the complete shipping_status status objects
     *
     * @return Status[]
     */
    public function getShippingStatusList(): array
    {
        $list = $this->getList();
        $result = [];

        foreach ($list as $entry => $color) {
            try {
                $result[] = $this->getShippingStatus($entry);
            } catch (Exception) {
            }
        }

        return $result;
    }

    /**
     * Return a shipping status
     *
     * @param int $id
     * @return Status|StatusUnknown
     *
     * @throws Exception
     */
    public function getShippingStatus(int $id): StatusUnknown | Status
    {
        if ($id === 0) {
            return new StatusUnknown();
        }

        return new Status($id);
    }

    /**
     * Delete / Remove a shipping status
     *
     * @param int|string $id
     *
     * @throws Exception
     * @throws QUI\Exception
     */
    public function deleteShippingStatus(int | string $id): void
    {
        Permission::checkPermission('quiqqer.shipping.delete');

        $Status = $this->getShippingStatus((int)$id);

        // remove translation
        QUI\Translator::delete(
            'quiqqer/shipping',
            'shipping.status.' . $Status->getId()
        );

        QUI\Translator::publish('quiqqer/shipping');

        // update config
        $Package = QUI::getPackage('quiqqer/shipping');
        $Config = $Package->getConfig();

        if ($Config === null) {
            throw new QUI\Exception('Missing quiqqer/shipping config');
        }

        $Config->del('shipping_status', (string)$Status->getId());
        $Config->save();
    }

    /**
     * Set auto-notification setting for a status
     *
     * @param int $id - ShippingStatus ID
     * @param bool $notify - Auto-notification if an order is changed to the given status?
     * @return void
     *
     * @throws Exception
     * @throws QUI\Exception
     */
    public function setShippingStatusNotification(int $id, bool $notify): void
    {
        Permission::checkPermission('quiqqer.shipping.edit');

        $Status = $this->getShippingStatus($id);

        // update config
        $Package = QUI::getPackage('quiqqer/shipping');
        $Config = $Package->getConfig();

        if ($Config === null) {
            throw new QUI\Exception('Missing quiqqer/shipping config');
        }

        $Config->setValue('shipping_status_notification', (string)$Status->getId(), $notify ? "1" : "0");
        $Config->save();
    }

    /**
     * Update a shipping status
     *
     * @param int $id
     * @param int|string $color
     * @param array<string, array<array-key, mixed>|string> $title
     *
     * @throws QUI\Exception
     */
    public function updateShippingStatus(int $id, int | string $color, array $title): void
    {
        Permission::checkPermission('quiqqer.shipping.edit');

        $Status = $this->getShippingStatus($id);

        // update translation
        $languages = QUI::availableLanguages();

        $data = [
            'package' => 'quiqqer/shipping',
            'datatype' => 'php,js',
            'html' => 1
        ];

        foreach ($languages as $language) {
            if (isset($title[$language])) {
                $data[$language] = $title[$language];
                $data[$language . '_edit'] = $title[$language];
            }
        }

        QUI\Translator::edit(
            'quiqqer/shipping',
            'shipping.status.' . $Status->getId(),
            'quiqqer/shipping',
            $data
        );

        QUI\Translator::publish('quiqqer/shipping');

        // update config
        $Package = QUI::getPackage('quiqqer/shipping');
        $Config = $Package->getConfig();

        if ($Config === null) {
            throw new QUI\Exception('Missing quiqqer/shipping config');
        }

        $Config->setValue('shipping_status', (string)$Status->getId(), $color);
        $Config->save();
    }

    /**
     * Create translations for status notification
     *
     * @param int $id
     * @return void
     */
    public function createNotificationTranslations(int $id): void
    {
        $data = [
            'package' => 'quiqqer/shipping',
            'datatype' => 'php,js',
            'html' => 1
        ];

        // translations
        $L = new QUI\Locale();
        $languages = QUI::availableLanguages();

        foreach ($languages as $language) {
            $L->setCurrent($language);
            $data[$language] = $L->get('quiqqer/shipping', 'shipping.status.notification.template');
        }

        try {
            // Check if translation already exists
            $translation = QUI\Translator::get('quiqqer/shipping', 'shipping.status.notification.' . $id);

            if (!empty($translation)) {
                return;
            }

            // ShippingStatus notification messages
            QUI\Translator::addUserVar(
                'quiqqer/shipping',
                'shipping.status.notification.' . $id,
                $data
            );

            QUI\Translator::publish('quiqqer/shipping');
        } catch (\Exception $Exception) {
            QUI\System\Log::writeException($Exception);
        }
    }

    /**
     * Notify customer about an Order status change (via e-mail)
     *
     * @param AbstractOrder $ErpEntity
     * @param int $statusId
     * @param string|null $message (optional) - Custom notification message [default: default status change message]
     * @return void
     *
     * @throws QUI\Exception
     */
    public function sendStatusChangeNotification(
        QUI\ERP\ErpEntityInterface $ErpEntity,
        int $statusId,
        null | string $message = null
    ): void {
        $Customer = $ErpEntity->getCustomer();
        $customerEmail = $Customer->getAttribute('email');

        if (empty($customerEmail)) {
            QUI\System\Log::addWarning(
                'Status change notification for entity #' . $ErpEntity->getPrefixedNumber() . ' cannot be sent'
                . ' because customer #' . $Customer->getUUID() . ' has no e-mail address.'
            );

            return;
        }

        if (empty($message)) {
            $Status = $this->getShippingStatus($statusId);
            $message = $Status->getStatusChangeNotificationText($ErpEntity);
        }

        $Mailer = new QUI\Mail\Mailer();
        $Locale = $ErpEntity->getCustomer()->getLocale();

        $Mailer->setSubject(
            $Locale->get('quiqqer/shipping', 'shipping.status.notification.subject', [
                'prefixedNumber' => $ErpEntity->getPrefixedNumber()
            ])
        );

        $Mailer->setBody($message);
        $Mailer->addRecipient($customerEmail);

        try {
            $Mailer->send();
            $ErpEntity->addStatusMail($message);
        } catch (\Exception $Exception) {
            QUI\System\Log::writeException($Exception);
        }
    }
}
