<?php

namespace Autogedal\Labels\Controller\Adminhtml\Label;

use Autogedal\Labels\Model\Attribute\ValueOptionsProvider;
use Autogedal\Labels\Model\ImageUploader;
use Autogedal\Labels\Model\LabelFactory;
use Autogedal\Labels\Model\SvgLabelVariantGenerator;
use Magento\Backend\App\Action;

class Save extends Action
{
    public const ADMIN_RESOURCE = 'Autogedal_Labels::labels';

    private $labelFactory;
    private $imageUploader;
    private $svgLabelVariantGenerator;
    private $valueOptionsProvider;

    public function __construct(
        Action\Context $context,
        LabelFactory $labelFactory,
        ImageUploader $imageUploader,
        SvgLabelVariantGenerator $svgLabelVariantGenerator,
        ValueOptionsProvider $valueOptionsProvider
    ) {
        parent::__construct($context);
        $this->labelFactory = $labelFactory;
        $this->imageUploader = $imageUploader;
        $this->svgLabelVariantGenerator = $svgLabelVariantGenerator;
        $this->valueOptionsProvider = $valueOptionsProvider;
    }

    public function execute()
    {
        $data = $this->getRequest()->getPostValue();
        if (!$data) {
            return $this->_redirect('*/*/');
        }

        $id = (int)($data['label_id'] ?? 0);
        $model = $this->labelFactory->create();

        if ($id) {
            $model->load($id);
            if (!$model->getId()) {
                $this->messageManager->addErrorMessage(__('This label no longer exists.'));
                return $this->_redirect('*/*/');
            }
        }

        // Process image fields from imageUploader components
        $data = $this->processImageData($data, 'prod_img');
        $data = $this->processShapeSelection($data, 'prod_img', 'prod_shape', 'prod_label_color');
        $data = $this->processDateTimeRange($data);
        $data = $this->processStoresForSave($data);
        $data = $this->processCategoryForSave($data);
        $data = $this->processSkuFilterForSave($data);
        $data = $this->processStockConditionForSave($data);
        $data = $this->processDateRangeToggleForSave($data);
        $data = $this->processPriceRangeToggleForSave($data);
        $data = $this->processCustomerGroupToggleForSave($data);
        $data = $this->processCustomerGroupsForSave($data);
        $data = $this->processAttrValueForSave($data);

        if ($id === 0) {
            $data = $this->applyNewLabelDefaults($data);
        }

        $model->addData($data);

        try {
            $model->save();
            $this->messageManager->addSuccessMessage(__('You saved the label.'));

            if ($this->getRequest()->getParam('back')) {
                return $this->_redirect('*/*/edit', ['label_id' => $model->getId()]);
            }

            return $this->_redirect('*/*/');
        } catch (\Throwable $e) {
            $this->messageManager->addErrorMessage($e->getMessage());
            $this->_getSession()->setFormData($data);
            return $this->_redirect('*/*/edit', ['label_id' => $id]);
        }
    }

    private function processImageData(array $data, string $fieldName): array
    {
        if (isset($data[$fieldName]) && is_array($data[$fieldName])) {
            if (!empty($data[$fieldName]['delete'])) {
                $data[$fieldName] = '';
            } elseif (isset($data[$fieldName][0]['name'])) {
                $data[$fieldName] = $data[$fieldName][0]['name'];
                // Move file from tmp to final location
                try {
                    $this->imageUploader->moveFileFromTmp($data[$fieldName]);
                } catch (\Exception $e) {
                    // ignore if already moved
                }
            } else {
                unset($data[$fieldName]);
            }
        }

        return $data;
    }

    private function processCategoryForSave(array $data): array
    {
        if (!array_key_exists('category', $data)) {
            return $data;
        }

        if (is_array($data['category'])) {
            $categoryIds = array_values(array_filter(array_map('trim', $data['category']), static function ($value) {
                return $value !== '';
            }));
            $data['category'] = implode(',', $categoryIds);
        } else {
            $data['category'] = trim((string)$data['category']);
        }

        if ($data['category'] !== '' && !array_key_exists('category_enabled', $data)) {
            $data['category_enabled'] = 1;
        }

        return $data;
    }

    private function processStoresForSave(array $data): array
    {
        if (!isset($data['stores'])) {
            $data['stores'] = ',0,';
            return $data;
        }

        if (is_array($data['stores'])) {
            $stores = array_values(array_filter(array_map('trim', $data['stores']), static function ($value) {
                return $value !== '';
            }));

            if ($stores === [] || in_array('0', $stores, true)) {
                $data['stores'] = ',0,';
                return $data;
            }

            $data['stores'] = ',' . implode(',', $stores) . ',';
        } else {
            $stores = trim((string)$data['stores']);
            if ($stores === '') {
                $data['stores'] = ',0,';
            } elseif (strpos($stores, ',') === false) {
                $data['stores'] = ',' . $stores . ',';
            } elseif ($stores[0] !== ',' || substr($stores, -1) !== ',') {
                $data['stores'] = ',' . trim($stores, ',') . ',';
            }
        }

        return $data;
    }

    private function processCustomerGroupsForSave(array $data): array
    {
        if (isset($data['customer_groups']) && is_array($data['customer_groups'])) {
            $data['customer_groups'] = implode(',', array_map('trim', $data['customer_groups']));
        }

        return $data;
    }

    private function processSkuFilterForSave(array $data): array
    {
        if (!array_key_exists('include_sku', $data)) {
            return $data;
        }

        $includeSku = trim((string)$data['include_sku']);
        $includeType = (int)($data['include_type'] ?? 0);

        if ($includeSku !== '' && $includeType === 0 && !array_key_exists('include_type', $data)) {
            $data['include_type'] = 2;
        }

        if ($includeSku === '' && $includeType !== 0 && !array_key_exists('include_type', $data)) {
            $data['include_type'] = 0;
        }

        return $data;
    }

    private function processStockConditionForSave(array $data): array
    {
        if (
            array_key_exists('stock_status', $data)
            || array_key_exists('stock_less', $data)
            || array_key_exists('stock_more', $data)
        ) {
            $hasStockCondition = trim((string)($data['stock_status'] ?? '')) !== ''
                || trim((string)($data['stock_less'] ?? '')) !== ''
                || trim((string)($data['stock_more'] ?? '')) !== '';

            if ($hasStockCondition && !array_key_exists('product_stock_enabled', $data)) {
                $data['product_stock_enabled'] = 1;
            }
        }

        return $data;
    }

    private function processDateRangeToggleForSave(array $data): array
    {
        $hasDateRange = trim((string)($data['from_date'] ?? '')) !== '' || trim((string)($data['to_date'] ?? '')) !== '';
        if ($hasDateRange && !array_key_exists('date_range_enabled', $data)) {
            $data['date_range_enabled'] = 1;
        }

        return $data;
    }

    private function processPriceRangeToggleForSave(array $data): array
    {
        if (array_key_exists('price_range_enabled', $data)) {
            return $data;
        }

        $hasPriceRange = trim((string)($data['from_price'] ?? '')) !== ''
            || trim((string)($data['to_price'] ?? '')) !== ''
            || (int)($data['by_price'] ?? 0) !== 0;

        if ($hasPriceRange) {
            $data['price_range_enabled'] = 1;
        }

        return $data;
    }

    private function processCustomerGroupToggleForSave(array $data): array
    {
        if (!array_key_exists('customer_groups', $data)) {
            return $data;
        }

        $hasGroups = false;
        if (is_array($data['customer_groups'])) {
            $hasGroups = array_filter(array_map('trim', $data['customer_groups']), static function ($value) {
                return $value !== '';
            }) !== [];
        } else {
            $hasGroups = trim((string)$data['customer_groups']) !== '';
        }

        if ($hasGroups && !array_key_exists('customer_group_enabled', $data)) {
            $data['customer_group_enabled'] = 1;
        }

        return $data;
    }

    private function processAttrValueForSave(array $data): array
    {
        if (!array_key_exists('attr_value', $data)) {
            return $data;
        }

        $attrCode = trim((string)($data['attr_code'] ?? ''));
        $attributeMode = null;
        if ($attrCode !== '') {
            $attributeMeta = $this->valueOptionsProvider->get($attrCode);
            $attributeMode = $attributeMeta['mode'] ?? 'input';
        }

        if (is_array($data['attr_value'])) {
            $data['attr_value'] = implode(',', array_filter(array_map('trim', $data['attr_value']), static function ($value) {
                return $value !== '';
            }));
        }

        if (!array_key_exists('attr_multi', $data)) {
            if ($attributeMode === 'multiselect') {
                $data['attr_multi'] = 1;
            } elseif ($attributeMode === 'select') {
                $data['attr_multi'] = 0;
            }
        } elseif ($attributeMode === 'multiselect' && (string)$data['attr_multi'] === '') {
            $data['attr_multi'] = 1;
        }

        if (array_key_exists('attr_multi', $data) && (int)$data['attr_multi'] === 0) {
            $data['attr_rule'] = 0;
        } elseif (!array_key_exists('attr_rule', $data)) {
            $data['attr_rule'] = 0;
        }

        return $data;
    }

    private function processDateTimeRange(array $data): array
    {
        $data['from_date'] = $this->combineDateAndTime(
            $data['from_date'] ?? null,
            $data['from_time'] ?? null,
            '00:00:00'
        );
        $data['to_date'] = $this->combineDateAndTime(
            $data['to_date'] ?? null,
            $data['to_time'] ?? null,
            '23:59:59'
        );

        unset($data['from_time'], $data['to_time']);

        return $data;
    }

    private function combineDateAndTime($dateValue, $timeValue, string $fallbackTime): string
    {
        $dateValue = trim((string)$dateValue);
        $timeValue = trim((string)$timeValue);

        if ($dateValue === '') {
            return '';
        }

        if ($timeValue === '') {
            $timeValue = $fallbackTime;
        }

        if (preg_match('/^\d{2}:\d{2}$/', $timeValue)) {
            $timeValue .= ':00';
        }

        if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $timeValue)) {
            $timeValue = $fallbackTime;
        }

        return $dateValue . ' ' . $timeValue;
    }

    private function processShapeSelection(array $data, string $imageField, string $shapeField, string $colorField): array
    {
        $shape = trim((string)($data[$shapeField] ?? ''));
        if ($shape === '') {
            unset($data[$shapeField]);
            return $data;
        }
        if (strtolower(pathinfo($shape, PATHINFO_EXTENSION)) !== 'svg') {
            unset($data[$shapeField]);
            return $data;
        }

        $color = trim((string)($data[$colorField] ?? ''));
        if ($color === '') {
            $color = '000000';
        }

        $labelId = isset($data['label_id']) ? (int)$data['label_id'] : null;
        $data[$imageField] = $this->svgLabelVariantGenerator->getVariantPath($shape, $color, $labelId);
        unset($data[$shapeField]);

        return $data;
    }

    /**
     * The UI omits a few non-null columns on create. Seed them with safe defaults
     * so the first insert can complete and assign an auto-increment ID.
     */
    private function applyNewLabelDefaults(array $data): array
    {
        $defaults = [
            'label_id' => null,
            'is_active' => 0,
            'is_single' => 0,
            'prod_pos' => 0,
            'is_new' => 0,
            'is_sale' => 0,
            'special_price_only' => 0,
            'include_type' => 0,
            'category_enabled' => 0,
            'attr_multi' => 0,
            'attr_rule' => 0,
            'product_stock_enabled' => 0,
            'stock_less' => 0,
            'stock_more' => 0,
            'stock_status' => 0,
            'date_range_enabled' => 0,
            'by_price' => 0,
            'price_range_enabled' => 0,
            'customer_group_enabled' => 0,
            'use_for_parent' => 0,
            'stores' => ',0,',
            'prod_txt' => '',
            'prod_img' => '',
            'prod_label_color' => '',
            'prod_style' => '',
            'prod_text_style' => '',
            'prod_image_width' => '',
            'prod_image_height' => '',
            'include_sku' => '',
            'category' => '',
            'attr_code' => '',
            'attr_value' => '',
            'from_date' => '',
            'to_date' => '',
            'from_price' => '',
            'to_price' => '',
            'customer_groups' => '',
        ];

        foreach ($defaults as $field => $defaultValue) {
            if (!array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '') {
                $data[$field] = $defaultValue;
            }
        }

        if ($data['label_id'] === null || $data['label_id'] === '') {
            unset($data['label_id']);
        }

        return $data;
    }
}
