<?php

namespace Autogedal\Labels\Model;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\MediaStorage\Helper\File\Storage\Database;
use Psr\Log\LoggerInterface;

class SvgLabelVariantGenerator
{
    private $mediaDirectory;
    private $logger;
    private $coreFileStorageDatabase;
    private $svgSanitizer;

    public function __construct(
        Filesystem $filesystem,
        Database $coreFileStorageDatabase,
        LoggerInterface $logger,
        SvgSanitizer $svgSanitizer
    ) {
        $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
        $this->coreFileStorageDatabase = $coreFileStorageDatabase;
        $this->logger = $logger;
        $this->svgSanitizer = $svgSanitizer;
    }

    public function getVariantPath(string $imagePath, string $color, ?int $labelId = null): string
    {
        $imagePath = ltrim($imagePath, '/');
        if ($imagePath === '' || strtolower(pathinfo($imagePath, PATHINFO_EXTENSION)) !== 'svg') {
            return $imagePath;
        }

        $normalizedColor = $this->normalizeColor($color);
        if ($normalizedColor === null) {
            return $imagePath;
        }

        $sourceRelative = 'autogedal_label/' . $imagePath;
        $sourceAbsolute = $this->mediaDirectory->getAbsolutePath($sourceRelative);
        if (!is_file($sourceAbsolute)) {
            return $imagePath;
        }

        $variantRelative = 'autogedal_label/generated/' . $this->buildVariantName($imagePath, $normalizedColor, $labelId);
        $variantAbsolute = $this->mediaDirectory->getAbsolutePath($variantRelative);
        if (is_file($variantAbsolute)) {
            return $variantRelative;
        }

        try {
            $svg = file_get_contents($sourceAbsolute);
            if ($svg === false) {
                return $imagePath;
            }
            $sanitized = $this->svgSanitizer->sanitize($svg);
            if ($sanitized === null) {
                return $imagePath;
            }

            $document = new \DOMDocument();
            $document->preserveWhiteSpace = false;
            $document->formatOutput = false;
            if (!$document->loadXML($sanitized, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING)) {
                return $imagePath;
            }

            $changed = false;
            foreach ($document->getElementsByTagName('*') as $node) {
                foreach (['fill', 'stroke'] as $attribute) {
                    if (!$node->hasAttribute($attribute)) {
                        continue;
                    }

                    $value = trim((string)$node->getAttribute($attribute));
                    if ($value === '' || $this->isNeutralColor($value)) {
                        continue;
                    }

                    $node->setAttribute($attribute, $normalizedColor);
                    $changed = true;
                }
            }

            if (!$changed) {
                return $imagePath;
            }

            $variantDir = dirname($variantAbsolute);
            if (!is_dir($variantDir) && !@mkdir($variantDir, 0775, true) && !is_dir($variantDir)) {
                return $imagePath;
            }

            $output = $document->saveXML();
            $output = is_string($output) ? $this->svgSanitizer->sanitize($output) : null;
            if ($output === null || file_put_contents($variantAbsolute, $output) === false) {
                return $imagePath;
            }

            try {
                $this->coreFileStorageDatabase->saveFile($variantRelative);
            } catch (\Exception $e) {
                $this->logger->warning(
                    sprintf('Failed to persist SVG label variant to DB storage for %s: %s', $variantRelative, $e->getMessage())
                );
            }

            return $variantRelative;
        } catch (\Throwable $e) {
            $this->logger->warning(
                sprintf('Failed to generate SVG label variant for %s: %s', $imagePath, $e->getMessage())
            );
            return $imagePath;
        }
    }

    private function normalizeColor(string $color): ?string
    {
        $color = trim($color);
        if ($color === '') {
            return null;
        }

        if ($color[0] !== '#') {
            $color = '#' . $color;
        }

        if (!preg_match('/^#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?$/', $color)) {
            return null;
        }

        return strtoupper($color);
    }

    private function isNeutralColor(string $value): bool
    {
        $value = strtolower(trim($value));
        return $value === '' || $value === 'none' || $value === 'transparent' || $value === '#fff' || $value === '#ffffff';
    }

    private function buildVariantName(string $imagePath, string $color, ?int $labelId = null): string
    {
        $baseName = pathinfo($imagePath, PATHINFO_FILENAME);
        $baseName = preg_replace('/[^a-zA-Z0-9_-]+/', '_', $baseName);
        $color = ltrim(strtolower($color), '#');
        $labelSuffix = $labelId !== null && $labelId > 0 ? '_label' . $labelId : '';

        return $baseName . '_' . $color . $labelSuffix . '.svg';
    }
}
