<?php

namespace Opencart\Admin\Controller\Extension\Alsendo;

require_once(DIR_EXTENSION . 'alsendo/src/Database/DatabaseMigrator.php');
require_once DIR_APPLICATION . "model/setting/setting.php";
require_once(DIR_EXTENSION . 'alsendo/src/DTO/Entity/AlsendoRegionEntity.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/Config.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/OrderShipment.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/Service.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/ShippingMethod.php');
require_once(DIR_EXTENSION . 'alsendo/src/Models/WrapperResult.php');
require_once(DIR_EXTENSION . 'alsendo/src/Providers/AdditionalSettingsDataProvider.php');
require_once(DIR_EXTENSION . 'alsendo/src/Providers/CommonDataProvider.php');
require_once(DIR_EXTENSION . 'alsendo/src/Providers/OrderShipmentProvider.php');
require_once(DIR_EXTENSION . 'alsendo/src/Providers/ShippingSettingsDataProvider.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/AdditionalSettingsRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/ConfigRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/OrderShipmentPackageRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/OrderShipmentRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/ServicesRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/SenderAddressRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/ShippingMethodRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Repositories/ShippingSettingsRepository.php');
require_once(DIR_EXTENSION . 'alsendo/src/Services/WrapperService.php');

use Opencart\Admin\Model\Setting\Setting;
use Opencart\Extension\Alsendo\Database\DatabaseMigrator;
use Opencart\Extension\Alsendo\DTO\Entity\AlsendoRegionEntity;
use Opencart\Extension\Alsendo\Models\ShippingMethod;
use Opencart\Extension\Alsendo\Providers\AdditionalSettingsDataProvider;
use Opencart\Extension\Alsendo\Providers\CommonDataProvider;
use Opencart\Extension\Alsendo\Providers\OrderShipmentProvider;
use Opencart\Extension\Alsendo\Providers\ShippingSettingsDataProvider;
use Opencart\Extension\Alsendo\Repositories\AdditionalSettingsRepository;
use Opencart\Extension\Alsendo\Repositories\ConfigRepository;
use Opencart\Extension\Alsendo\Repositories\OrderShipmentPackageRepository;
use Opencart\Extension\Alsendo\Repositories\OrderShipmentRepository;
use Opencart\Extension\Alsendo\Repositories\SenderAddressRepository;
use Opencart\Extension\Alsendo\Repositories\ServicesRepository;
use Opencart\Extension\Alsendo\Repositories\ShippingMethodRepository;
use Opencart\Extension\Alsendo\Repositories\ShippingSettingsRepository;
use Opencart\Extension\Alsendo\Services\WrapperService;
use Opencart\System\Engine\Controller;

class AlsendoShipment extends Controller
{
    private AdditionalSettingsDataProvider $additionalSettingsDataProvider;
    private AdditionalSettingsRepository $additionalSettingsRepository;
    private CommonDataProvider $commonDataProvider;
    private OrderShipmentProvider $orderShipmentProvider;
    private ShippingSettingsDataProvider $shippingSettingsDataProvider;

    private ConfigRepository $configRepository;
    private OrderShipmentPackageRepository $orderShipmentPackageRepository;
    private OrderShipmentRepository $orderShipmentRepository;
    private ServicesRepository $servicesRepository;
    private ShippingMethodRepository $shippingMethodRepository;
    private ShippingSettingsRepository $shippingSettingsRepository;
    private SenderAddressRepository $senderAddressRepository;

    private WrapperService $wrapperService;
    private AlsendoRegionEntity $currentRegion;
    private DatabaseMigrator $databaseMigrator;

    public function __construct($registry)
    {
        parent::__construct($registry);

        $this->databaseMigrator = new DatabaseMigrator($registry, $this->db,\DB_PREFIX);

        if (!$this->databaseMigrator->isInstalled()) {
            return;
        }

        $this->load->model('extension/alsendo/module/alsendo_region');
        /** @var AlsendoRegionEntity $currentRegion */
        $this->currentRegion = $this->model_extension_alsendo_module_alsendo_region->getCurrentRegion();

        $this->configRepository = new ConfigRepository($this->db, \DB_PREFIX);
        $this->orderShipmentPackageRepository = new OrderShipmentPackageRepository($this->db, \DB_PREFIX);
        $this->orderShipmentRepository = new OrderShipmentRepository($this->db, \DB_PREFIX);
        $this->servicesRepository = new ServicesRepository($this->db, \DB_PREFIX);
        $this->shippingMethodRepository = new ShippingMethodRepository($registry, $this->db, \DB_PREFIX);
        $this->shippingSettingsRepository = new ShippingSettingsRepository($this->db, \DB_PREFIX);
        $this->senderAddressRepository = new SenderAddressRepository($this->db, \DB_PREFIX);

        $this->commonDataProvider = new CommonDataProvider($this->language, $this->url, $this->session);
        $this->orderShipmentProvider = new OrderShipmentProvider($this->orderShipmentRepository, $this->orderShipmentPackageRepository);
        $this->shippingSettingsDataProvider = new ShippingSettingsDataProvider($this->shippingSettingsRepository);

        $this->additionalSettingsRepository = new AdditionalSettingsRepository($this->db, \DB_PREFIX);
        $this->additionalSettingsDataProvider = new AdditionalSettingsDataProvider($this->additionalSettingsRepository);

        $this->wrapperService = new WrapperService(
            $registry,
            DIR_EXTENSION . 'alsendo/',
            $this->servicesRepository,
            $this->additionalSettingsDataProvider,
            $this->senderAddressRepository
        );

        if (isset($this->document)) {
            $this->document->addScript('https://map.alsendo.com/v8.5/main.js');
            $this->document->addStyle('https://map.alsendo.com/v8.5/main.css');
        }
    }

    public function index(): void {
        $this->document->addStyle('/extension/alsendo/admin/view/css/style.css');

        if (isset($this->request->post['action'])) {
            $this->handleAjaxActions();
            return;
        }

        $config = $this->configRepository->getConfig();
        if ($config->isComplete()) {
            $existingServices = $this->servicesRepository->getServicesIndexedById($this->currentRegion);
            if (empty($existingServices)) {
                try {
                    $result = $this->wrapperService->getAvailableServices($config, $this->currentRegion);
                    if ($result->isSuccess()) {
                        $now = date('Y-m-d H:i:s');
                        $settingModel = new Setting($this->registry);
                        $settingModel->editSetting('alsendo_courier_service_refresh_date', ['alsendo_courier_service_refresh_date_value' => $now]);
                    }
                } catch (\Throwable $e) {
                }
            }
        }
        $data = $this->commonDataProvider->getData($config);
        $data['current_store_currency'] = $this->config->get('config_currency');
        $data = array_merge($data, $this->shippingSettingsDataProvider->getData());

        $this->load->language('extension/alsendo/main');

        $this->document->setTitle($this->language->get('heading_title'));

        $data['breadcrumbs'] = [];
        $data['breadcrumbs'][] = [
            'text' => $this->language->get('text_home'),
            'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
        ];

        $data['breadcrumbs'][] = [
            'text' => 'Alsendo',
            'href' => 'javascript:void(0)'
        ];

        $data['breadcrumbs'][] = [
            'text' => $this->language->get('general_settings_header'),
            'href' => $this->url->link('extension/alsendo/alsendo_shipment', 'user_token=' . $this->session->data['user_token'])
        ];

        $data['save'] = $this->url->link('extension/alsendo/alsendo_shipment.save', 'user_token=' . $this->session->data['user_token']);
        $data['back'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=shipping');

        $data['shipping_alsendo_status'] = $this->config->get('shipping_alsendo_status');
        $data['shipping_alsendo_sort_order'] = $this->config->get('shipping_alsendo_sort_order');
        $data['shipping_alsendo_tax_class_id'] = $this->config->get('shipping_alsendo_tax_class_id');

        $this->load->model('localisation/tax_class');
        $data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();

        $data['header'] = $this->load->controller('common/header');
        $data['column_left'] = $this->load->controller('common/column_left');
        $data['footer'] = $this->load->controller('common/footer');

        $settingModel = new Setting($this->registry);
        $data['alsendo_courier_service_refresh_date_value'] = $settingModel->getValue('alsendo_courier_service_refresh_date_value');
        $data['payments'] = $this->getPayments();

        $this->load->model('extension/alsendo/module/payment_shipment');
        $data['payments_map'] = $this->model_extension_alsendo_module_payment_shipment->getPaymentsForShipmentMap();

        $data['allow_map_selection'] = false;

        $data['current_region'] = $this->currentRegion->code;

        $this->response->setOutput($this->load->view('extension/alsendo/module/alsendo_shipment', $data));
    }

    public function save(): void {
        $this->load->language('extension/alsendo/main');

        $json = [];

        if (!$this->user->hasPermission('modify', 'extension/alsendo/alsendo_shipment')) {
            $json['error'] = $this->language->get('error_permission');
        }

        if (!$json) {
            $this->load->model('setting/setting');

            $settings = [
                'shipping_alsendo_sort_order' => (int)($this->request->post['shipping_alsendo_sort_order'] ?? 0),
                'shipping_alsendo_tax_class_id' => (int)($this->request->post['shipping_alsendo_tax_class_id'] ?? 0),
                'shipping_alsendo_methods' => json_encode($this->request->post['shipping_methods'] ?? []),
                'shipping_alsendo_status' => 1,
            ];

            $this->model_setting_setting->editSetting('shipping_alsendo', $settings);

            $json['success'] = $this->language->get('text_success');
        }

        $this->response->addHeader('Content-Type: application/json');
        $this->response->setOutput(json_encode($json));
    }

    public function showOrderShipmentList(): void {
        $this->load->language('sale/order');
        $this->load->language('extension/alsendo/main');

        $this->document->setTitle($this->language->get('heading_title'));

        if (isset($this->request->get['filter_order_id'])) {
            $filter_order_id = (int)$this->request->get['filter_order_id'];
        } else {
            $filter_order_id = '';
        }

        if (isset($this->request->get['filter_customer_id'])) {
            $filter_customer_id = $this->request->get['filter_customer_id'];
        } else {
            $filter_customer_id = '';
        }

        if (isset($this->request->get['filter_customer'])) {
            $filter_customer = $this->request->get['filter_customer'];
        } else {
            $filter_customer = '';
        }

        if (isset($this->request->get['filter_store_id'])) {
            $filter_store_id = (int)$this->request->get['filter_store_id'];
        } else {
            $filter_store_id = '';
        }

        if (isset($this->request->get['filter_order_status'])) {
            $filter_order_status = $this->request->get['filter_order_status'];
        } else {
            $filter_order_status = '';
        }

        if (isset($this->request->get['filter_order_status_id'])) {
            $filter_order_status_id = (int)$this->request->get['filter_order_status_id'];
        } else {
            $filter_order_status_id = '';
        }

        if (isset($this->request->get['filter_total'])) {
            $filter_total = $this->request->get['filter_total'];
        } else {
            $filter_total = '';
        }

        if (isset($this->request->get['filter_date_from'])) {
            $filter_date_from = $this->request->get['filter_date_from'];
        } else {
            $filter_date_from = '';
        }

        if (isset($this->request->get['filter_date_to'])) {
            $filter_date_to = $this->request->get['filter_date_to'];
        } else {
            $filter_date_to = '';
        }

        $url = '';

        if (isset($this->request->get['filter_order_id'])) {
            $url .= '&filter_order_id=' . $this->request->get['filter_order_id'];
        }

        if (isset($this->request->get['filter_customer_id'])) {
            $url .= '&filter_customer_id=' . (int)$this->request->get['filter_customer_id'];
        }

        if (isset($this->request->get['filter_customer'])) {
            $url .= '&filter_customer=' . urlencode(html_entity_decode($this->request->get['filter_customer'], ENT_QUOTES, 'UTF-8'));
        }

        if (isset($this->request->get['filter_store_id'])) {
            $url .= '&filter_store_id=' . (int)$this->request->get['filter_store_id'];
        }

        if (isset($this->request->get['filter_order_status'])) {
            $url .= '&filter_order_status=' . $this->request->get['filter_order_status'];
        }

        if (isset($this->request->get['filter_order_status_id'])) {
            $url .= '&filter_order_status_id=' . (int)$this->request->get['filter_order_status_id'];
        }

        if (isset($this->request->get['filter_total'])) {
            $url .= '&filter_total=' . $this->request->get['filter_total'];
        }

        if (isset($this->request->get['filter_date_from'])) {
            $url .= '&filter_date_from=' . $this->request->get['filter_date_from'];
        }

        if (isset($this->request->get['filter_date_to'])) {
            $url .= '&filter_date_to=' . $this->request->get['filter_date_to'];
        }

        if (isset($this->request->get['sort'])) {
            $url .= '&sort=' . $this->request->get['sort'];
        }

        if (isset($this->request->get['order'])) {
            $url .= '&order=' . $this->request->get['order'];
        }

        if (isset($this->request->get['page'])) {
            $url .= '&page=' . $this->request->get['page'];
        }

        $data['breadcrumbs'] = [];
        $data['breadcrumbs'][] = [
            'text' => $this->language->get('text_home'),
            'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
        ];

        $data['breadcrumbs'][] = [
            'text' => 'Alsendo',
            'href' => 'javascript:void(0)'
        ];

        $data['breadcrumbs'][] = [
            'text' => $this->language->get('alsendo_shipment_list_text'),
            'href' => $this->url->link('extension/alsendo/alsendo_order', 'user_token=' . $this->session->data['user_token'])
        ];


        $data['add'] = $this->url->link('sale/order.info', 'user_token=' . $this->session->data['user_token'] . $url);
        $data['delete'] = $this->url->link('sale/order.delete', 'user_token=' . $this->session->data['user_token']);
        $data['invoice'] = $this->url->link('sale/order.invoice', 'user_token=' . $this->session->data['user_token']);
        $data['shipping'] = $this->url->link('sale/order.shipping', 'user_token=' . $this->session->data['user_token']);

        $data['list'] = $this->getList();

        $data['stores'] = [];

        $data['stores'][] = [
            'store_id' => 0,
            'name'     => $this->language->get('text_default')
        ];

        $this->load->model('setting/store');

        $stores = $this->model_setting_store->getStores();

        foreach ($stores as $store) {
            $data['stores'][] = [
                'store_id' => $store['store_id'],
                'name'     => $store['name']
            ];
        }

        $this->load->model('localisation/order_status');

        $data['order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();

        $data['filter_order_id'] = $filter_order_id;
        $data['filter_customer_id'] = $filter_customer_id;
        $data['filter_customer'] = $filter_customer;
        $data['filter_store_id'] = $filter_store_id;
        $data['filter_order_status'] = $filter_order_status;
        $data['filter_order_status_id'] = $filter_order_status_id;
        $data['filter_total'] = $filter_total;
        $data['filter_date_from'] = $filter_date_from;
        $data['filter_date_to'] = $filter_date_to;

        $data['user_token'] = $this->session->data['user_token'];

        $data['header'] = $this->load->controller('common/header');
        $data['column_left'] = $this->load->controller('common/column_left');
        $data['footer'] = $this->load->controller('common/footer');

        $this->response->setOutput($this->load->view('extension/alsendo/module/alsendo_shipment_show_order_shipment_list', $data));
    }

    public function list(): void
    {
        $this->load->language('sale/order');
        $this->load->language('extension/alsendo/main');

        $this->response->setOutput($this->getList());
    }

    protected function getList(): string
    {
        if (isset($this->request->get['filter_date_from'])) {
            $filter_date_from = $this->request->get['filter_date_from'];
        } else {
            $filter_date_from = '';
        }

        if (isset($this->request->get['filter_date_to'])) {
            $filter_date_to = $this->request->get['filter_date_to'];
        } else {
            $filter_date_to = '';
        }

        if (isset($this->request->get['sort'])) {
            $sort = (string)$this->request->get['sort'];
        } else {
            $sort = 'o.order_id';
        }

        if (isset($this->request->get['order'])) {
            $order = (string)$this->request->get['order'];
        } else {
            $order = 'DESC';
        }

        if (isset($this->request->get['page'])) {
            $page = (int)$this->request->get['page'];
        } else {
            $page = 1;
        }

        $url = '';

        if (isset($this->request->get['filter_date_from'])) {
            $url .= '&filter_date_from=' . $this->request->get['filter_date_from'];
        }

        if (isset($this->request->get['filter_date_to'])) {
            $url .= '&filter_date_to=' . $this->request->get['filter_date_to'];
        }

        if (isset($this->request->get['sort'])) {
            $url .= '&sort=' . $this->request->get['sort'];
        }

        if (isset($this->request->get['order'])) {
            $url .= '&order=' . $this->request->get['order'];
        }

        if (isset($this->request->get['page'])) {
            $url .= '&page=' . $this->request->get['page'];
        }

        $data['action'] = $this->url->link('sale/order.list', 'user_token=' . $this->session->data['user_token'] . $url);

        $data['shipments'] = [];

        $filterData = [
            'filter_date_from'       => $filter_date_from,
            'filter_date_to'         => $filter_date_to,
            'sort'                   => $sort,
            'order'                  => $order,
            'start'                  => ($page - 1) * (int)$this->config->get('config_pagination_admin'),
            'limit'                  => (int) $this->config->get('config_pagination_admin'),
            'region_id'              => $this->currentRegion->id,
        ];

        $this->load->model('sale/order');

        $alsendoOrderTotal = $this->orderShipmentProvider->getTotalCount();

        $results = $this->orderShipmentProvider->getMultipleShipmentsWithPackages($filterData);
        foreach ($results as $result) {
            $data['shipments'][] = [
                'id'              => $result['id'],
                'order_id'        => $result['order_id'],
                'status'          => $result['status'],
                'package'         => $result['package'] ?? [],
                'data'            => json_decode($result['data'], true),
                'created_at'      => date($this->language->get('date_format_short'), strtotime($result['created_at'])),
                'updated_at'      => date($this->language->get('date_format_short'), strtotime($result['updated_at'])),
                'view'            => $this->url->link('sale/order.info', 'user_token=' . $this->session->data['user_token'] . '&order_id=' . $result['order_id'] . $url)
            ];
        }

        $url = '';

        if ($order == 'ASC') {
            $url .= '&order=DESC';
        } else {
            $url .= '&order=ASC';
        }

        $url = '';

        if (isset($this->request->get['sort'])) {
            $url .= '&sort=' . $this->request->get['sort'];
        }

        if (isset($this->request->get['order'])) {
            $url .= '&order=' . $this->request->get['order'];
        }

        $data['pagination'] = $this->load->controller('common/pagination', [
            'total' => $alsendoOrderTotal,
            'page'  => $page,
            'limit' => $this->config->get('config_pagination_admin'),
            'url'   => $this->url->link('extension/alsendo/alsendo_shipment.list', 'user_token=' . $this->session->data['user_token'] . $url . '&page={page}')
        ]);

        $data['results'] = sprintf($this->language->get('text_pagination'), ($alsendoOrderTotal) ? (($page - 1) * $this->config->get('config_pagination_admin')) + 1 : 0, ((($page - 1) * $this->config->get('config_pagination_admin')) > ($alsendoOrderTotal - $this->config->get('config_pagination_admin'))) ? $alsendoOrderTotal : ((($page - 1) * $this->config->get('config_pagination_admin')) + $this->config->get('config_pagination_admin')), $alsendoOrderTotal, ceil($alsendoOrderTotal / $this->config->get('config_pagination_admin')));

        $data['sort'] = $sort;
        $data['order'] = $order;

        return $this->load->view('extension/alsendo/module/alsendo_shipment_get_list', $data);
    }

    private function handleAjaxActions(): void
    {
        $action = $this->request->post['action'];

        switch ($action) {
            case 'get_shipping_methods':
                $this->handleGetShippingMethods();
                break;
            case 'update_shipping_method':
                $this->handleUpdateShippingMethod();
                break;
            case 'remove_shipping_method':
                $this->handleRemoveShippingMethod();
                break;
            case 'get_all_services_for_selection':
                $this->handleGetAllServicesForSelection();
                break;
            case 'save_all_shipping_methods':
                $this->handleSaveAllShippingMethods();
                break;
            case 'save_service_selection':
                $this->handleSaveServiceSelection();
                break;
            case 'get_shipping_services':
                $this->handleGetShippingServices();
                break;
            case 'add_new_shipping_method':
                $this->handleAddNewShippingMethod();
                break;
            case 'save_payment_mapping':
                $this->savePaymentMapping();
                break;
            default:
                $this->sendJsonResponse(['error' => 'Invalid action']);
        }
    }

    private function handleGetShippingServices(): void
    {
        $config = $this->configRepository->getConfig();

        $result = $this->wrapperService->getAvailableServices($config, $this->currentRegion);

        if ($result->isSuccess()) {
            $apiServices = $result->getData()['services'];
            $dbServices = $this->servicesRepository->getServicesIndexedByExternalId($this->currentRegion);

            $mergedServices = [];
            foreach ($apiServices as $apiService) {
                $serviceId = $apiService['external_id'];
                $isSelected = isset($dbServices[$serviceId]) && (bool) $dbServices[$serviceId]['is_selected'];

                $mergedServices[] = array_merge($apiService, ['is_selected' => $isSelected]);
            }

            $now = date('Y-m-d H:i:s');
            $settingModel = new Setting($this->registry);
            $settingModel->editSetting('alsendo_courier_service_refresh_date', ['alsendo_courier_service_refresh_date_value' => $now]);


            $this->sendJsonResponse(['success' => true, 'services' => $mergedServices, 'refresh_date' => $now]);
        } else {
            $this->sendJsonResponse(['error' => $result->getError()]);
        }
    }

    private function handleSaveServiceSelection(): void
    {
        $selectedIds = $this->request->post['selected_ids'] ?? [];

        try {
            $this->servicesRepository->updateServiceSelection($selectedIds);
            $this->shippingMethodRepository->clearUnselectedServiceReferences();
            $this->sendJsonResponse(['success' => true]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to save service selection: ' . $e->getMessage()]);
        }
    }

    private function handleGetShippingMethods(): void
    {
        $selectedServices = $this->servicesRepository->getSelectedServicesByRegion($this->currentRegion);

        try {
            $shippingMethods = $this->shippingMethodRepository->getAllShippingMethodsByRegion($this->currentRegion);
            $servicesData = $this->servicesRepository->getServicesIndexedById($this->currentRegion);
            $selectedServices = $this->servicesRepository->getSelectedServicesByRegion($this->currentRegion);

            $methodsData = [];

            foreach ($shippingMethods as $method) {
                $serviceId = $method->getServiceId();
                $service = $serviceId && isset($servicesData[$serviceId]) ? $servicesData[$serviceId] : null;

                $hasMap = $method->getHasMap();

                if ($this->currentRegion->code === 'poland') {
                    if (!empty($serviceId)) {
                        $hasMap = $service && !empty($service['to_point']);
                    }
                }

                $methodRow = [
                    'id' => $method->getId(),
                    'service_id' => $serviceId ? (int)$serviceId : null,
                    'service_name' => $service ? $service['name'] : null,
                    'custom_name' => $method->getName(),
                    'price' => $method->getPrice(),
                    'has_map' => $hasMap
                ];
                if ($this->currentRegion->code === 'czechia') {
                    $methodRow['shipping_via_pickup_point'] = $method->getShippingViaPickupPoint();
                    $methodRow['pickup_request'] = $method->getPickupRequest();
                }
                $methodsData[] = $methodRow;
            }

            $selectedServicesData = [];
            foreach ($selectedServices as $selectedService) {
                $arr = $selectedService->toArray();
                $selectedServicesData[] = [
                    'id' => $selectedService->getId(),
                    'name' => $selectedService->getName(),
                    'point_to_point' => (int)($arr['point_to_point'] ?? 0),
                    'door_to_point' => (int)($arr['door_to_point'] ?? 0),
                    'point_to_door' => (int)($arr['point_to_door'] ?? 0),
                    'door_to_door' => (int)($arr['door_to_door'] ?? 0),
                    'ship_via_pickup_point_allowed' => $selectedService->isShipViaPickupPointAllowed(),
                    'pickup_request_allowed' => $selectedService->isPickupRequestAllowed()
                ];
            }

            $this->sendJsonResponse(['success' => true, 'methods' => $methodsData, 'selected_services' => $selectedServicesData]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to get shipping methods: ' . $e->getMessage()]);
        }
    }

    private function handleUpdateShippingMethod(): void
    {
        $methodId = $this->request->post['method_id'] ?? '';
        $serviceId = $this->request->post['service_id'] ?? null;
        $customName = trim($this->request->post['custom_name'] ?? '');
        $price = $this->request->post['price'] ?? null;

        if (empty($methodId)) {
            $this->sendJsonResponse(['error' => 'Method ID is required']);
            return;
        }

        if (empty($customName)) {
            $this->sendJsonResponse(['error' => 'Custom name is required']);
            return;
        }

        try {
            $priceValue = null;
            if ($price !== null && $price !== '') {
                $priceValue = (float)$price;
                if ($priceValue < 0) {
                    $this->sendJsonResponse(['error' => 'Price must be a positive number']);
                    return;
                }
            }

            $serviceIdValue = (!empty($serviceId) && $serviceId !== '') ? $serviceId : null;

            $shippingMethod = $this->shippingMethodRepository->getShippingMethodById((int)$methodId);
            if (!$shippingMethod) {
                $this->sendJsonResponse(['error' => 'Shipping method not found']);
                return;
            }

            $shippingMethod->setServiceId($serviceIdValue);
            $shippingMethod->setName($customName);
            $shippingMethod->setPrice($priceValue);

            $this->shippingMethodRepository->updateShippingMethod($shippingMethod);
            $this->sendJsonResponse(['success' => true]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to update shipping method: ' . $e->getMessage()]);
        }
    }

    private function handleRemoveShippingMethod(): void
    {
        $methodId = $this->request->post['method_id'] ?? '';

        if (empty($methodId)) {
            $this->sendJsonResponse(['error' => 'Method ID is required']);
            return;
        }

        try {
            $this->shippingMethodRepository->deleteShippingMethod((int)$methodId);
            $this->sendJsonResponse(['success' => true]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to remove shipping method: ' . $e->getMessage()]);
        }
    }

    private function handleGetAllServicesForSelection(): void
    {
        try {
            $allServices = $this->servicesRepository->getAllServicesByRegion($this->currentRegion);
            $services = [];

            foreach ($allServices as $service) {
                $services[] = [
                    'id' => $service->getId(),
                    'name' => $service->getName(),
                    'has_map' => $service->isDeliveryToPoint(),
                    'is_selected' => $service->isSelected()
                ];
            }

            $this->sendJsonResponse(['success' => true, 'services' => $services]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to get services: ' . $e->getMessage()]);
        }
    }

    private function handleSaveAllShippingMethods(): void
    {
        $methods = $this->request->post['methods'] ?? [];

        if (empty($methods)) {
            $this->sendJsonResponse(['error' => 'No methods data provided']);
            return;
        }

        try {
            foreach ($methods as $method) {
                $methodId = $method['method_id'] ?? '';
                $serviceId = $method['id'] ?? null;
                $customName = trim($method['custom_name'] ?? '');
                $price = $method['price'] ?? null;

                if (empty($methodId) || empty($customName)) {
                    continue;
                }

                $priceValue = null;
                if ($price !== null && $price !== '') {
                    $priceValue = (float)$price;
                    if ($priceValue < 0) {
                        $priceValue = null;
                    }
                }

                $serviceIdValue = !empty($serviceId) ? $serviceId : null;
                $hasMap = false;

                if ($serviceIdValue) {
                    $service = $this->servicesRepository->getServiceById((int) $serviceIdValue);
                    if ($service) {
                        $hasMap = $service->isDeliveryToPoint();
                    }
                }

                if ($serviceIdValue === null) {
                    $hasMap = filter_var($method['has_map'] ?? false, FILTER_VALIDATE_BOOLEAN);
                }

                $shippingMethod = $this->shippingMethodRepository->getShippingMethodById((int)$methodId);

                if ($shippingMethod) {
                    $shippingMethod->setServiceId($serviceIdValue);
                    $shippingMethod->setName($customName);
                    $shippingMethod->setPrice($priceValue);
                    $shippingMethod->setHasMap($hasMap);

                    if ($this->currentRegion->code === 'czechia') {
                        $shippingMethod->setShippingViaPickupPoint(isset($method['shipping_via_pickup_point']) && $method['shipping_via_pickup_point'] !== '' && $method['shipping_via_pickup_point'] !== null ? (int)$method['shipping_via_pickup_point'] : null);
                        $shippingMethod->setPickupRequest(isset($method['pickup_request']) && $method['pickup_request'] !== '' ? (int)$method['pickup_request'] : null);
                    }

                    $this->shippingMethodRepository->updateShippingMethod($shippingMethod);
                }
            }

            $this->sendJsonResponse(['success' => true]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to save shipping methods: ' . $e->getMessage()]);
        }
    }

    private function handleAddNewShippingMethod(): void
    {
        try {
            $shippingMethod = new ShippingMethod($this->currentRegion->id);
            $newId = $this->shippingMethodRepository->saveShippingMethod($shippingMethod);
            $this->sendJsonResponse(['success' => true, 'id' => $newId]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => 'Failed to create new shipping method: ' . $e->getMessage()]);
        }
    }

    public function savePaymentMapping(): void
    {
        $this->load->language('extension/alsendo/main');
        $shipmentPaymentMap = $this->request->post['mappings'] ?? [];
        try {
            $this->load->model('extension/alsendo/module/payment_shipment');
            $this->model_extension_alsendo_module_payment_shipment->savePaymentsForShipment($shipmentPaymentMap);
            $this->sendJsonResponse(['success' => true, 'message' => $this->language->get('success_payment_mapping_saved')]);
        } catch (\Exception $e) {
            $this->sendJsonResponse(['error' => $e->getMessage()]);
        }
    }

    private function getPayments(): array {
        $this->load->model('setting/extension');

        $payments = $this->model_setting_extension->getExtensionsByType('payment');

        foreach ($payments as &$payment) {
            $this->load->language('extension/'.$payment['extension'].'/payment/' . $payment['code'], $payment['code']);
            $payment['name'] = $this->language->get($payment['code'] . '_heading_title');

            if (empty($payment['name'])) {
                $payment['name'] = $payment['code'];
            }
        }

        return $payments;
    }

    private function sendJsonResponse(array $data): void
    {
        $this->response->addHeader('Content-Type: application/json');
        $this->response->setOutput(json_encode($data));
    }
}