import SwiftUI
import WebKit

struct MermaidWebView: UIViewRepresentable {
    private static let mermaidJS = BundledWebResources.contents(of: "mermaid.min.js")

    let code: String
    @Binding var height: CGFloat
    @Environment(\.colorScheme) private var colorScheme

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIView(context: Context) -> WKWebView {
        let config = WKWebViewConfiguration()
        let controller = WKUserContentController()
        controller.add(context.coordinator, name: "heightReporter")
        config.userContentController = controller

        let webView = WKWebView(frame: .zero, configuration: config)
        webView.isOpaque = false
        webView.backgroundColor = .clear
        webView.scrollView.backgroundColor = .clear
        webView.scrollView.isScrollEnabled = false
        webView.navigationDelegate = context.coordinator
        return webView
    }

    // swiftlint:disable:next function_body_length
    func updateUIView(_ webView: WKWebView, context: Context) {
        let theme = colorScheme == .dark ? "dark" : "default"
        let key = "\(code)\n---\n\(theme)"
        guard key != context.coordinator.lastRenderedKey else { return }
        context.coordinator.lastRenderedKey = key

        let safeCode = code
            .replacingOccurrences(of: "&", with: "&amp;")
            .replacingOccurrences(of: "<", with: "&lt;")
            .replacingOccurrences(of: ">", with: "&gt;")
            .replacingOccurrences(of: "\"", with: "&quot;")
            .replacingOccurrences(of: "'", with: "&#39;")

        let mermaidJS = Self.mermaidJS
        let csp =
            "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:;"
        let html = """
        <!DOCTYPE html>
        <html>
        <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
        <meta http-equiv="Content-Security-Policy" content="\(csp)">
        <style>
            body {
                margin: 0;
                padding: 8px;
                background: transparent;
                display: flex;
                justify-content: center;
            }
            .mermaid {
                overflow-x: auto;
            }
            .mermaid svg {
                max-width: 100%;
                height: auto;
            }
        </style>
        </head>
        <body>
        <pre class="mermaid">
        \(safeCode)
        </pre>
        <script>\(mermaidJS)</script>
        <script>
            mermaid.initialize({
                startOnLoad: true,
                theme: '\(theme)',
                securityLevel: 'strict'
            });
            // Report height after rendering
            const observer = new MutationObserver(() => {
                const svg = document.querySelector('.mermaid svg');
                if (svg) {
                    observer.disconnect();
                    setTimeout(() => {
                        const height = document.body.scrollHeight;
                        window.webkit.messageHandlers.heightReporter.postMessage(height);
                    }, 100);
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
            // Fallback timeout
            setTimeout(() => {
                const height = document.body.scrollHeight;
                window.webkit.messageHandlers.heightReporter.postMessage(height);
            }, 3000);
        </script>
        </body>
        </html>
        """

        webView.loadHTMLString(html, baseURL: nil)
    }

    static func dismantleUIView(_ webView: WKWebView, coordinator _: Coordinator) {
        webView.configuration.userContentController.removeScriptMessageHandler(forName: "heightReporter")
    }

    class Coordinator: NSObject, WKScriptMessageHandler, WKNavigationDelegate {
        let parent: MermaidWebView
        var lastRenderedKey: String?

        init(parent: MermaidWebView) {
            self.parent = parent
        }

        func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) {
            if let height = message.body as? CGFloat, height > 0 {
                DispatchQueue.main.async { [weak self] in
                    self?.parent.height = height
                }
            }
        }

        // swiftlint:disable:next line_length
        func webView(_: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            if navigationAction.navigationType == .linkActivated {
                decisionHandler(.cancel)
            } else {
                decisionHandler(.allow)
            }
        }
    }
}
