<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AddCspNonceToScripts
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        // 只處理 HTML 響應
        if ($response->headers->get('Content-Type') === 'text/html; charset=UTF-8') {
            $content = $response->getContent();
            
            // 儲存提取出的樣式內容
            $styles = [];
            $styleCounter = 0;

            // 第一步：處理內聯樣式，將 style 轉換為 class
            $content = preg_replace_callback(
                '/<([a-z][a-z0-9]*)\b([^>]*)style=["\']([^"\']+)["\']([^>]*)>/i',
                function ($matches) use (&$styles, &$styleCounter) {
                    $tag = $matches[1]; // 標籤名稱，例如 div
                    $beforeAttrs = trim($matches[2]); // style 前的屬性
                    $styleContent = $matches[3]; // 內聯樣式內容
                    $afterAttrs = trim($matches[4]); // style 後的屬性

                    // 生成唯一的 class 名稱
                    $className = 'inline-style-' . $styleCounter++;
                    $styles[$className] = $styleContent;

                    // 組合新的標籤，保留其他屬性並添加 class
                    $newAttrs = $beforeAttrs . ($beforeAttrs ? ' ' : '') . 'class="' . $className . '"' . ($afterAttrs ? ' ' : '') . $afterAttrs;
                    return '<' . $tag . ' ' . trim($newAttrs) . '>';
                },
                $content
            );

            // 第二步：為 <script> 和 <style> 標籤添加 nonce
            $content = preg_replace_callback(
                '/<(script|style)\b([^>]*)>(.*?)<\/\1>/is',
                function ($matches) {
                    $tag = $matches[1];
                    $attributes = $matches[2];
                    $contentInside = $matches[3];

                    if (strpos($attributes, 'nonce=') !== false) {
                        return $matches[0];
                    }

                    $nonce = csp_nonce();
                    return '<' . $tag . ' ' . $attributes . ' nonce="' . $nonce . '">' . $contentInside . '</' . $tag . '>';
                },
                $content
            );

            // 第三步：將提取的樣式追加為 <style> 標籤
            if (!empty($styles)) {
                $styleBlock = '<style nonce="' . csp_nonce() . '">' . PHP_EOL;
                foreach ($styles as $className => $styleContent) {
                    $styleBlock .= '.' . $className . ' {' . $styleContent . '}' . PHP_EOL;
                }
                $styleBlock .= '</style>';

                // 將樣式塊插入到 </head> 之前（如果有 head），否則插入到文件末尾
                $content = str_contains($content, '</head>')
                    ? str_replace('</head>', $styleBlock . '</head>', $content)
                    : $content . $styleBlock;
            }
            
            $response->setContent($content);
        }

        return $response;
    }
}
