<?php

use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Email\EmailGroupTypeEnum;
use KupShop\KupShopBundle\Email\OrderMessageEmail;
use KupShop\KupShopBundle\Email\UserMessagesInterface;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Mail\Email;
use KupShop\KupShopBundle\Util\Mail\EmailLocator;
use KupShop\KupShopBundle\Util\Mail\EmailSender;
use KupShop\KupShopBundle\Util\Mail\SMSSender;
use KupShop\OrderingBundle\Util\Attachment\AttachmentLocator;
use KupShop\ReturnsBundle\Util\ReturnsUtil;
use Symfony\Component\Mime\Exception\RfcComplianceException;

$main_class = 'AdminEmails';

class AdminEmails extends Window
{
    protected $template = 'window/emails.tpl';

    private $languageContext;

    public function __construct()
    {
        $this->languageContext = ServiceContainer::getService(LanguageContext::class);
    }

    public function hasRights($name = null)
    {
        switch ($name) {
            case self::RIGHT_DUPLICATE:
            case self::RIGHT_DELETE:
                return false;
            default:
                return true;
        }
    }

    public function get_vars()
    {
        $vars = parent::get_vars();

        $settings = Settings::createFromDB();

        $pageVars['data'] = [
            'order_send_received_mail' => $settings->order_send_received_mail,
            'order_send_status_mail' => $settings->order_send_status_mail,
            'order_send_to_shopkeeper' => $settings->order_send_to_shopkeeper,
            'order_shopkeeper_mail' => $settings->order_shopkeeper_mail,
            'default_email' => $settings->order_shopkeeper_mail,
            'smtp' => $settings->smtp ?? [],
            'email_default_signature' => $settings->email_default_signature ?? [],
            'email_allowed_recipient_domains' => $settings->email_allowed_recipient_domains ?? '',
        ];

        /** @var Email $email */
        $email = ServiceContainer::getService(Email::class);
        $pageVars['email'] = $email;

        /** @var SMSSender $smsSender */
        $smsSender = ServiceContainer::getService(SMSSender::class);
        $pageVars['SMSSenderBackend'] = $smsSender->getBackend();

        // Get email groups from enum, so we can display them in right order
        array_map(function ($enum) use (&$pageVars) {
            $pageVars['emails_messages'][$enum->value] = ['doNotShow' => true];
        }, EmailGroupTypeEnum::cases());

        $default_emails = [];
        foreach ($email->getDefaultTypes() as $type) {
            $emailService = $email->getServiceByType($type);
            if ($emailService::getGroup() == EmailGroupTypeEnum::HIDDEN->value) {
                continue;
            }

            if ($emailService instanceof UserMessagesInterface) {
                // Fetch UserMessage types for group
                $pageVars['messages_types'][$emailService::getGroup()] = $emailService::getType();
                $pageVars['emails_messages'][$emailService::getGroup()] = $emailService->getMessages($this->languageContext->getDefaultId());
                foreach ($pageVars['emails_messages'][$emailService::getGroup()] as &$message) {
                    $message['attachments'] = $this->prepareAttachments($message['attachments']);
                }
                continue;
            }
            $default_emails[$emailService::getGroup()][$type] = $emailService->getEmailTemplate($this->languageContext->getDefaultId());
            $default_emails[$emailService::getGroup()][$type]['isAnswer'] = $emailService->isAnswer ?? null;
            if (empty($default_emails[$emailService::getGroup()][$type]['id'])) {
                $default_emails[$emailService::getGroup()][$type]['id'] = rand(-100, -200);
            }
            $default_emails[$emailService::getGroup()][$type]['name'] = $emailService::getName();
            $default_emails[$emailService::getGroup()][$type]['attachments'] = $this->prepareAttachments($default_emails[$emailService::getGroup()][$type]['attachments']);
            $default_emails[$emailService::getGroup()][$type]['default_template'] = $emailService->getDefaultEmail();
            $default_emails[$emailService::getGroup()][$type]['attachmentsGroup'] = $emailService::getGroup();
        }

        // Sort groups by desired order
        $sorted_default_emails = array_merge(array_flip([
            EmailGroupTypeEnum::ORDER->value,
            EmailGroupTypeEnum::FORMS->value,
            EmailGroupTypeEnum::RETURN->value,
            EmailGroupTypeEnum::RECLAMATION->value,
            EmailGroupTypeEnum::OTHER->value,
        ]), $default_emails);

        // Filter empty groups
        $pageVars['emails'] = array_intersect_key($sorted_default_emails, $default_emails);

        if (!empty($pageVars['emails'][EmailGroupTypeEnum::OTHER->value][Email::TYPE_BASIC_TEMPLATE]['email'])) {
            $pageVars['data']['default_email'] = $pageVars['emails'][EmailGroupTypeEnum::OTHER->value][Email::TYPE_BASIC_TEMPLATE]['email'];
        }

        $pageVars['statuses'] = [
            // -100 - hardcoded non existing status for storno, so it can be selected
            'order' => Config::get()['Order']['Status']['global'] + ['-100' => 'storno'],
        ];

        if (findModule(\Modules::RETURNS)) {
            $pageVars['statuses']['return'] = ServiceContainer::getService(ReturnsUtil::class)->getStatuses();
        }

        // attachments
        $attachmentLocator = ServiceContainer::getService(AttachmentLocator::class);

        $pageVars['attachments'] = $attachmentLocator->getAttachments('ALL');

        $vars['body'] = $pageVars;

        return $vars;
    }

    private function prepareAttachments($attachments)
    {
        if (!empty($attachments)) {
            return json_decode($attachments, true);
        }

        return [];
    }

    public function handle()
    {
        $this->tryRights('EDIT');

        $data = getVal('data');
        $Submit = getVal('Submit');
        $acn = getVal('acn');
        if (!empty($data) && !empty($Submit)) {
            $ErrStr = $this->saveSettings($data);

            redirect('launch.php?s=emails.php&acn=edit&flap='.getVal('flap').'&ErrStr='.$ErrStr);
        } elseif (str_starts_with($acn ?? '', 'SendTestEmail_')) {
            $this->sendTestEmail(str_replace('SendTestEmail_', '', $acn));
        } else {
            Base::handle();
        }
    }

    public function handlePlaceholders()
    {
        $type = getVal('type');
        $emailLocator = ServiceContainer::getService(EmailLocator::class);
        $emailService = $emailLocator->getEmailService($type);

        // TODO: HACK Bez testEmail padají applyPlaceholders, protože v nich lidi šahají na data (->getOrder()), který tam v tohle případě nejsou.
        // TODO: HACK Proto volám testEmail, abych nasetoval nějaký testovací data a nepadalo to. Ale applyPlaceholders by nemělo záviset na datech.
        $order_message = getVal('order_message');
        if ($emailService instanceof OrderMessageEmail) {
            $emailService->setOrderMessage($order_message);
        }
        $emailService->testEmail();

        foreach ($emailLocator->getEmailRegisters() as $register) {
            $register->applyPlaceholders($emailService);
        }

        $placeholders = $emailService::getPlaceholders();
        foreach ($emailService->getEntityPlaceholders() as $placeholder) {
            $placeholders[$emailService::getType()][$placeholder->code] = ['text' => $placeholder->description];
        }

        $smarty = createSmarty(true, true);
        $smarty->assign([
            'type' => $type,
            'name' => $emailService::getName(),
            'placeholders' => $placeholders,
        ]);

        $smarty->display('window/emails.placeholders.tpl');
        exit;
    }

    public function handleTest()
    {
        $type = getVal('type');
        $emailLocator = ServiceContainer::getService(EmailLocator::class);
        $emailService = $emailLocator->getEmailService($type);
        $typeTestEmail = $emailService->getTestType();
        $order_message = getVal('order_message');

        if ($emailService instanceof OrderMessageEmail) {
            $emailService->setOrderMessage($order_message);
        }

        if ($typeTestEmail && $entityID = getVal('entityID')) {
            $emailService->setTestEntity($entityID);
        }

        try {
            if ($type == 'BASIC_TEMPLATE') {
                $message = ['body' => '<p>Testovací email.</p>', 'subject' => 'Testovací email'];
                $message = $emailService->renderEmail($message);
                $message['body'] = replacePlaceholders($message['body'], [], [$emailService, 'replacePlaceholdersItem']);
            } else {
                $message = $emailService->testEmail();
            }
        } catch (InvalidArgumentException $e) {
            $this->returnError($e->getMessage());
        }

        $smarty = createSmarty(true, true);
        $smarty->assign([
            'type' => $type,
            'typeTestEmail' => $typeTestEmail,
            'entityID' => $entityID ?? '',
            'email' => $message,
            'order_message' => $order_message,
            'placeholders' => $emailService::getPlaceholders() ?? '',
        ]);

        $smarty->display('window/emails.preview.tpl');
        exit;
    }

    public function sendTestEmail($id)
    {
        $this->saveSettings(getVal('data'));

        $emailSender = ServiceContainer::getService(EmailSender::class);
        try {
            $email = Settings::getDefault()->order_shopkeeper_mail;
            $testEmail = explode(',', getVal('data')['smtp'][$id]['allowed_senders']);
            $testEmail = trim(reset($testEmail));
            if (!$testEmail || $testEmail == '*') {
                $testEmail = $email;
            }
            $message = $emailSender->createMessage($testEmail, $email, 'Testovací email', 'Testovací email pro kontrolu nastavení SMTP serveru.', 'text/html');
            $emailSender->realSendMessage($message);
        } catch (RfcComplianceException $e) {
            $this->returnError('Nelze odeslat testovací e-mail. E-mailová adresa nemá správný formát');
        } catch (Throwable $e) {
            $error = $e->getMessage();
            $this->returnError("Nelze odeslat testovací email: {$error}");
        }

        $this->returnOK('Testovací zpráva odeslána.');
    }

    protected function saveSettings($data)
    {
        $settings = Settings::createFromDB();
        $edited = [];

        $types = ['emails_messages'];

        array_map(function ($enum) use (&$types) {
            $types[] = $enum->value;
        }, EmailGroupTypeEnum::cases());

        foreach ($data as $type => $values) {
            if (!in_array($type, $types)) {
                continue;
            }
            foreach ($values as $id => $email) {
                if ($id == 0) {
                    continue;
                }

                switch ($email['type']) {
                    case 'ORDER_CREATE':
                        $edited['order_send_received_mail'] = $email['enabled'];
                        break;
                    case 'ORDER_STATUS_CHANGE':
                        $edited['order_send_status_mail'] = $email['enabled'];
                        break;
                    case 'ORDER_CREATE_ADMIN':
                        $edited['order_send_to_shopkeeper'] = $email['enabled'];
                        break;
                }

                $email['order_status'] = $email['order_status'] == '' ? null : $email['order_status'];
                $email['name'] = trim($email['name'] ?? '');

                if (!empty($email['attachments'])) {
                    $email['attachments'] = json_encode($email['attachments']);
                } else {
                    $email['attachments'] = null;
                }

                if (empty($email['body'])) {
                    continue;
                }

                /** @var Email $email */
                $emailService = ServiceContainer::getService(Email::class);
                $email['body'] = $emailService->stripEmail($email['body']);

                if (!empty($email['delete'])) {
                    if ($email['system_msg'] != 'Y') {
                        $this->deleteSQL('emails', ['id' => $id]);
                    }
                    continue;
                }

                if ($email['type'] == \KupShop\KupShopBundle\Email\BaseEmail::getType() && empty($email['email'])) {
                    $email['email'] = $settings->order_shopkeeper_mail;
                }

                if ($id > 0) {
                    $this->updateSQL('emails', $email, ['id' => $id]);
                } else {
                    $this->insertSQL('emails', $email, ['id']);
                }
            }
        }

        $edited['order_shopkeeper_mail'] = $data['order_shopkeeper_mail'];
        $edited['bounce_email'] = $data['bounce_email'];
        $edited['archive_email'] = $data['archive_email'];
        $edited['email_allowed_recipient_domains'] = $data['email_allowed_recipient_domains'];

        if (!empty($data['smtp'])) {
            $edited['smtp'] = $data['smtp'];
        }
        if (!empty($data['email_default_signature'])) {
            $edited['email_default_signature'] = $data['email_default_signature'];
        }

        $data['elninoEmailTemplates'] = array_filter($data['elninoEmailTemplates'] ?? [], function ($v) {
            return $v['ticketState'] !== false && !empty($v['statuses']) && !empty($v['userMessage']) && empty($v['delete']);
        });
        if (!empty($data['elninoEmailTemplates'])) {
            $data['elninoEmailTemplates'] = array_combine(range(1, count($data['elninoEmailTemplates'])), array_values($data['elninoEmailTemplates']));
        }
        $edited['elninoEmailTemplates'] = json_encode($data['elninoEmailTemplates']);

        $settings->loadFromArray($edited);

        if ($settings->saveToDB()) {
            $ErrStr = $GLOBALS['txt_str']['status']['saved'];
        } else {
            $ErrStr = $GLOBALS['txt_str']['status']['scripterror'];
        }

        Settings::clearCache(true);

        return $ErrStr;
    }
}
