<?php

namespace App\Services\Ticket;

use Illuminate\Support\Str;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Table\TableExtension;
use League\CommonMark\MarkdownConverter;

/**
 * PRC-683 — Ticket içerik biçimlendirme tek karar noktası (çift yön).
 *
 * Katman-1 pipeline (inbound mail HTML VE outbound WYSIWYG/Quill HTML aynı yolu
 * paylaşır):
 *
 *   HTML → sanitizeHtml() (script/style/on* + tehlikeli protokol temizliği)
 *        → toMarkdown() (league/html-to-markdown, yoksa hafif fallback)
 *        → ticket_replies.message (MARKDOWN) + content_format='markdown'
 *
 *   gösterim: Markdown → toSafeHtml() (CommonMark, RAW-HTML OFF + unsafe-link OFF)
 *           → güvenli HTML (agent + client view).
 *
 * Renk bilinçli olarak taşınmaz (Markdown sınırı); piksel-birebir orijinal .eml
 * katmanında (TicketOriginalEmail) durur.
 */
class TicketContentFormatter
{
    /**
     * Gelen/yazılan HTML'i Markdown'a çevir (saklama yönü).
     * Önce XSS-tehlikeli düğümleri temizler, sonra Markdown üretir.
     */
    public function htmlToMarkdown(string $html): string
    {
        $html = $this->sanitizeHtml($html);

        $markdown = $this->convertToMarkdown($html);

        // Fazla boş satırları toparla (3+ → 2), satır-sonu boşluğu at.
        $markdown = preg_replace('/\n{3,}/', "\n\n", $markdown);
        $markdown = preg_replace('/[ \t]+$/m', '', (string) $markdown);

        return trim((string) $markdown);
    }

    /**
     * Markdown'ı güvenli HTML'e render et (gösterim yönü).
     * RAW-HTML OFF + unsafe-link OFF: ham <script>/onload/tracking-pixel geçmez.
     */
    public function markdownToSafeHtml(string $markdown): string
    {
        $config = [
            'html_input' => 'escape',       // RAW-HTML OFF — ham HTML kaçırılır, çalıştırılmaz
            'allow_unsafe_links' => false,  // javascript:/data: linkleri kırpılır
            'max_nesting_level' => 25,
            'renderer' => [
                'soft_break' => "<br>\n", // e-posta düz metninde alt satırları koru
            ],
        ];

        $environment = new Environment($config);
        $environment->addExtension(new CommonMarkCoreExtension());
        $environment->addExtension(new AutolinkExtension());
        $environment->addExtension(new TableExtension());

        $converter = new MarkdownConverter($environment);

        return (string) $converter->convert($markdown);
    }

    /**
     * Düz-metin (content_format='plain') gösterimi — geriye uyum.
     * Eski satırlar bozulmadan görüntülenir.
     */
    public function plainToSafeHtml(string $text): string
    {
        return nl2br(e($text));
    }

    /**
     * content_format'a göre doğru render yolunu seç.
     */
    public function render(string $message, ?string $format): string
    {
        return $format === 'markdown'
            ? $this->markdownToSafeHtml($message)
            : $this->plainToSafeHtml($message);
    }

    /**
     * XSS-tehlikeli düğüm temizliği (Markdown'a çevirmeden ÖNCE).
     * <script>/<style>/<iframe>/<object> gövdeleriyle silinir; tüm on* event
     * attribute'ları + javascript:/vbscript:/data: (resim hariç) protokolleri
     * kaldırılır. Tam bir HTMLPurifier değil — amaç Markdown'a giden ara HTML'i
     * script'ten arındırmak; nihai güvenlik render'da (RAW-HTML OFF) sağlanır.
     */
    public function sanitizeHtml(string $html): string
    {
        if (trim($html) === '') {
            return '';
        }

        // Tehlikeli blok elementleri gövdeleriyle sil.
        $html = preg_replace(
            '#<(script|style|iframe|object|embed|form|link|meta|base)\b[^>]*>.*?</\1>#is',
            '',
            $html
        );
        // Kapanışsız tehlikeli tekil etiketler.
        $html = preg_replace(
            '#<(script|style|iframe|object|embed|form|link|meta|base)\b[^>]*/?>#is',
            '',
            (string) $html
        );

        // on* event handler attribute'ları (onclick=, onload=, ...).
        $html = preg_replace('#\son[a-z]+\s*=\s*"[^"]*"#is', '', (string) $html);
        $html = preg_replace("#\son[a-z]+\s*=\s*'[^']*'#is", '', (string) $html);
        $html = preg_replace('#\son[a-z]+\s*=\s*[^\s>]+#is', '', (string) $html);

        // Tehlikeli protokoller (href/src içi).
        $html = preg_replace('#(href|src)\s*=\s*(["\']?)\s*(javascript|vbscript):[^"\'>\s]*\2#is', '$1=$2#$2', (string) $html);

        return (string) $html;
    }

    /**
     * HTML → Markdown çevirisi. league/html-to-markdown mevcutsa onu kullanır;
     * değilse hafif etiket-eşlemeli fallback (bold/italic/link/list/blockquote/
     * heading/br/paragraph). Fallback renk taşımaz (zaten Markdown sınırı).
     */
    private function convertToMarkdown(string $html): string
    {
        if (class_exists(\League\HTMLToMarkdown\HtmlConverter::class)) {
            $converter = new \League\HTMLToMarkdown\HtmlConverter([
                'strip_tags' => true,
                'remove_nodes' => 'script style head title meta link',
                'hard_break' => true,
                'use_autolinks' => false,
            ]);

            return $converter->convert($html);
        }

        return $this->fallbackHtmlToMarkdown($html);
    }

    /**
     * Bağımlılıksız hafif HTML→Markdown (league/html-to-markdown yoksa).
     * Kapsam: heading, bold, italic, link, img, ul/ol/li, blockquote, br, p, hr.
     */
    private function fallbackHtmlToMarkdown(string $html): string
    {
        $html = str_replace(["\r\n", "\r"], "\n", $html);

        // Blok kırıcılar.
        $html = preg_replace('#<br\s*/?>#i', "\n", $html);
        $html = preg_replace('#</p>#i', "\n\n", $html);
        $html = preg_replace('#<p\b[^>]*>#i', '', $html);
        $html = preg_replace('#<hr\s*/?>#i', "\n\n---\n\n", $html);

        // Heading h1-h6.
        for ($i = 1; $i <= 6; $i++) {
            $prefix = str_repeat('#', $i) . ' ';
            $html = preg_replace_callback(
                "#<h{$i}\b[^>]*>(.*?)</h{$i}>#is",
                fn ($m) => "\n\n" . $prefix . trim(strip_tags($m[1])) . "\n\n",
                $html
            );
        }

        // Kalın / italik.
        $html = preg_replace('#<(strong|b)\b[^>]*>(.*?)</\1>#is', '**$2**', $html);
        $html = preg_replace('#<(em|i)\b[^>]*>(.*?)</\1>#is', '*$2*', $html);

        // Link.
        $html = preg_replace_callback(
            '#<a\b[^>]*href\s*=\s*["\']([^"\']*)["\'][^>]*>(.*?)</a>#is',
            fn ($m) => '[' . trim(strip_tags($m[2])) . '](' . $m[1] . ')',
            (string) $html
        );

        // Resim.
        $html = preg_replace_callback(
            '#<img\b[^>]*>#is',
            function ($m) {
                $src = '';
                $alt = '';
                if (preg_match('#src\s*=\s*["\']([^"\']*)["\']#i', $m[0], $s)) {
                    $src = $s[1];
                }
                if (preg_match('#alt\s*=\s*["\']([^"\']*)["\']#i', $m[0], $a)) {
                    $alt = $a[1];
                }

                return $src !== '' ? '![' . $alt . '](' . $src . ')' : '';
            },
            (string) $html
        );

        // Blockquote.
        $html = preg_replace_callback(
            '#<blockquote\b[^>]*>(.*?)</blockquote>#is',
            function ($m) {
                $inner = trim(strip_tags($m[1]));
                $lines = array_map(fn ($l) => '> ' . $l, explode("\n", $inner));

                return "\n\n" . implode("\n", $lines) . "\n\n";
            },
            (string) $html
        );

        // Sırasız liste.
        $html = preg_replace_callback(
            '#<ul\b[^>]*>(.*?)</ul>#is',
            function ($m) {
                $items = [];
                if (preg_match_all('#<li\b[^>]*>(.*?)</li>#is', $m[1], $li)) {
                    foreach ($li[1] as $item) {
                        $items[] = '- ' . trim(strip_tags($item));
                    }
                }

                return "\n" . implode("\n", $items) . "\n";
            },
            (string) $html
        );

        // Sıralı liste.
        $html = preg_replace_callback(
            '#<ol\b[^>]*>(.*?)</ol>#is',
            function ($m) {
                $items = [];
                if (preg_match_all('#<li\b[^>]*>(.*?)</li>#is', $m[1], $li)) {
                    $n = 1;
                    foreach ($li[1] as $item) {
                        $items[] = ($n++) . '. ' . trim(strip_tags($item));
                    }
                }

                return "\n" . implode("\n", $items) . "\n";
            },
            (string) $html
        );

        // Kalan tüm etiketleri sök + entity decode.
        $text = strip_tags($html);
        $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');

        return $text;
    }

    /**
     * Markdown içine güvenli resim satırı üret (inline cid: çıkarımı için).
     * Alt-metin + parantez-içi attachment URL.
     */
    public function markdownImage(string $altText, string $url): string
    {
        $altText = trim(preg_replace('/[\[\]\r\n]+/', ' ', $altText)) ?: 'image';

        return '![' . $altText . '](' . $url . ')';
    }
}
