import SwiftUI
import Foundation

struct MarkdownRenderer {
    static func renderToAttributedString(_ markdown: String) -> AttributedString {
        // Basic markdown parsing
        var attributedString = AttributedString(markdown)

        // Apply basic styling
        attributedString = processHeaders(attributedString)
        attributedString = processBold(attributedString)
        attributedString = processItalic(attributedString)
        attributedString = processCode(attributedString)
        attributedString = processLinks(attributedString)
        attributedString = processLists(attributedString)

        return attributedString
    }

    private static func processHeaders(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process headers (# ## ### etc.)
    // Use (?m) for multiline so ^ and $ match line boundaries; avoid deprecated anchorsMatchLines
    let headerPattern = "(?m)^(#{1,6})\\s+(.+)$"
    let regex = try? NSRegularExpression(pattern: headerPattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            let headerLevelRange = match.range(at: 1)
            let headerTextRange = match.range(at: 2)

            if let headerLevelSwiftRange = Range(headerLevelRange, in: string),
               let headerTextSwiftRange = Range(headerTextRange, in: string) {

                let headerLevel = string[headerLevelSwiftRange].count
                let headerText = String(string[headerTextSwiftRange])

                let fontSize: CGFloat = {
                    switch headerLevel {
                    case 1: return 24
                    case 2: return 20
                    case 3: return 18
                    case 4: return 16
                    case 5: return 14
                    case 6: return 12
                    default: return 16
                    }
                }()

                if let range = Range(match.range, in: result) {
                    var headerAttributedText = AttributedString(headerText)
                    headerAttributedText.font = .system(size: fontSize, weight: .bold)
                    result.replaceSubrange(range, with: headerAttributedText)
                }
            }
        }

        return result
    }

    private static func processBold(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process bold (**text** or __text__)
        let boldPattern = "(\\*\\*|__)(.+?)\\1"
        let regex = try? NSRegularExpression(pattern: boldPattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            let boldTextRange = match.range(at: 2)

            if let boldTextSwiftRange = Range(boldTextRange, in: string) {
                let boldText = String(string[boldTextSwiftRange])

                if let range = Range(match.range, in: result) {
                    var boldAttributedText = AttributedString(boldText)
                    boldAttributedText.font = .boldSystemFont(ofSize: 16)
                    result.replaceSubrange(range, with: boldAttributedText)
                }
            }
        }

        return result
    }

    private static func processItalic(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process italic (*text* or _text_)
        let italicPattern = "(?<!\\*)\\*([^*]+)\\*(?!\\*)|(?<!_)_([^_]+)_(?!_)"
        let regex = try? NSRegularExpression(pattern: italicPattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            // Get the captured group that actually matched
            let italicTextRange = match.range(at: 1).location != NSNotFound ? match.range(at: 1) : match.range(at: 2)

            if let italicTextSwiftRange = Range(italicTextRange, in: string) {
                let italicText = String(string[italicTextSwiftRange])

                if let range = Range(match.range, in: result) {
                    var italicAttributedText = AttributedString(italicText)
                    italicAttributedText.font = .italicSystemFont(ofSize: 16)
                    result.replaceSubrange(range, with: italicAttributedText)
                }
            }
        }

        return result
    }

    private static func processCode(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process inline code (`code`)
        let codePattern = "`([^`]+)`"
        let regex = try? NSRegularExpression(pattern: codePattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            let codeTextRange = match.range(at: 1)

            if let codeTextSwiftRange = Range(codeTextRange, in: string) {
                let codeText = String(string[codeTextSwiftRange])

                if let range = Range(match.range, in: result) {
                    var codeAttributedText = AttributedString(codeText)
                    codeAttributedText.font = .monospacedSystemFont(ofSize: 14, weight: .regular)
                    codeAttributedText.backgroundColor = .gray.opacity(0.2)
                    result.replaceSubrange(range, with: codeAttributedText)
                }
            }
        }

        return result
    }

    private static func processLinks(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process links [text](url)
        let linkPattern = "\\[([^\\]]+)\\]\\(([^\\)]+)\\)"
        let regex = try? NSRegularExpression(pattern: linkPattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            let linkTextRange = match.range(at: 1)
            let linkURLRange = match.range(at: 2)

            if let linkTextSwiftRange = Range(linkTextRange, in: string),
               let linkURLSwiftRange = Range(linkURLRange, in: string) {

                let linkText = String(string[linkTextSwiftRange])
                let linkURL = String(string[linkURLSwiftRange])

                if let range = Range(match.range, in: result) {
                    var linkAttributedText = AttributedString(linkText)
                    linkAttributedText.foregroundColor = .blue
                    linkAttributedText.underlineStyle = .single
                    if let url = URL(string: linkURL) {
                        linkAttributedText.link = url
                    }
                    result.replaceSubrange(range, with: linkAttributedText)
                }
            }
        }

        return result
    }

    private static func processLists(_ text: AttributedString) -> AttributedString {
        var result = text
        let string = String(result.characters)

        // Process unordered lists (- item or * item)
    let listPattern = "(?m)^\\s*[-*+]\\s+(.+)$"
    let regex = try? NSRegularExpression(pattern: listPattern, options: [])

        let matches = regex?.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count)) ?? []

        for match in matches.reversed() {
            let listItemRange = match.range(at: 1)

            if let listItemSwiftRange = Range(listItemRange, in: string) {
                let listItemText = String(string[listItemSwiftRange])

                if let range = Range(match.range, in: result) {
                    let bulletText = "• " + listItemText
                    var listAttributedText = AttributedString(bulletText)
                    listAttributedText.font = .systemFont(ofSize: 16)
                    result.replaceSubrange(range, with: listAttributedText)
                }
            }
        }

        return result
    }
}

// MARK: - SwiftUI Views

struct MarkdownView: View {
    let text: String

    var body: some View {
        ScrollView {
            Text(MarkdownRenderer.renderToAttributedString(text))
                .textSelection(.enabled)
                .padding()
        }
    }
}

struct MarkdownEditor: View {
    @Binding var text: String
    @State private var isPreviewMode: Bool = false

    var body: some View {
        VStack {
            // Toolbar
            HStack {
                Button(action: {
                    isPreviewMode.toggle()
                }) {
                    HStack {
                        Image(systemName: isPreviewMode ? "pencil" : "eye")
                        Text(isPreviewMode ? "edit" : "preview")
                    }
                }
                .font(.caption)

                Spacer()

                if !isPreviewMode {
                    Menu {
                        Button("bold") {
                            insertMarkdown("**", "**")
                        }
                        Button("italic") {
                            insertMarkdown("*", "*")
                        }
                        Button("code") {
                            insertMarkdown("`", "`")
                        }
                        Button("link") {
                            insertMarkdown("[", "](url)")
                        }
                        Button("header") {
                            insertMarkdown("# ", "")
                        }
                        Button("list_item") {
                            insertMarkdown("- ", "")
                        }
                    } label: {
                        Image(systemName: "textformat")
                    }
                    .font(.caption)
                }
            }
            .padding(.horizontal)
            .padding(.bottom, 8)

            // Content
            if isPreviewMode {
                MarkdownView(text: text)
            } else {
                TextEditor(text: $text)
                    .font(.system(.body, design: .monospaced))
            }
        }
    }

    private func insertMarkdown(_ prefix: String, _ suffix: String) {
        text += prefix + "text" + suffix
    }
}

// MARK: - Markdown Utilities

extension MarkdownRenderer {
    static func extractPlainText(_ markdown: String) -> String {
        var plainText = markdown

        // Remove headers
        plainText = plainText.replacingOccurrences(of: "^#{1,6}\\s+", with: "", options: .regularExpression)

        // Remove bold and italic
        plainText = plainText.replacingOccurrences(of: "\\*\\*([^*]+)\\*\\*", with: "$1", options: .regularExpression)
        plainText = plainText.replacingOccurrences(of: "__([^_]+)__", with: "$1", options: .regularExpression)
        plainText = plainText.replacingOccurrences(of: "\\*([^*]+)\\*", with: "$1", options: .regularExpression)
        plainText = plainText.replacingOccurrences(of: "_([^_]+)_", with: "$1", options: .regularExpression)

        // Remove inline code
        plainText = plainText.replacingOccurrences(of: "`([^`]+)`", with: "$1", options: .regularExpression)

        // Remove links
        plainText = plainText.replacingOccurrences(of: "\\[([^\\]]+)\\]\\([^\\)]+\\)", with: "$1", options: .regularExpression)

        // Remove list markers
    plainText = plainText.replacingOccurrences(of: "(?m)^\\s*[-*+]\\s+", with: "", options: .regularExpression)

        return plainText.trimmingCharacters(in: .whitespacesAndNewlines)
    }

    static func estimateReadingTime(_ markdown: String) -> Int {
        let plainText = extractPlainText(markdown)
        let wordCount = plainText.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count
        let wordsPerMinute = 200 // Average reading speed
        return max(1, wordCount / wordsPerMinute)
    }

    static func getWordCount(_ markdown: String) -> Int {
        let plainText = extractPlainText(markdown)
        return plainText.components(separatedBy: .whitespacesAndNewlines).filter { !$0.isEmpty }.count
    }

    static func validateMarkdown(_ markdown: String) -> [MarkdownValidationError] {
        var errors: [MarkdownValidationError] = []

        // Check for unclosed bold/italic markers
        let boldCount = markdown.components(separatedBy: "**").count - 1
        if boldCount % 2 != 0 {
            errors.append(.unclosedbold)
        }

        let italicCount = markdown.components(separatedBy: "*").count - 1 - boldCount
        if italicCount % 2 != 0 {
            errors.append(.unclosedItalic)
        }

        // Check for unclosed code blocks
        let codeCount = markdown.components(separatedBy: "`").count - 1
        if codeCount % 2 != 0 {
            errors.append(.unclosedCode)
        }

        // Check for malformed links
        let malformedLinkPattern = "\\[[^\\]]*\\]\\([^\\)]*$|\\[[^\\]]*$\\)|^[^\\[]*\\]\\([^\\)]*\\)"

        if let regex = try? NSRegularExpression(pattern: malformedLinkPattern, options: []) {
            let matches = regex.matches(in: markdown, options: [], range: NSRange(location: 0, length: markdown.utf16.count))
            if !matches.isEmpty {
                errors.append(.malformedLink)
            }
        }

        return errors
    }
}

enum MarkdownValidationError: Error, LocalizedError {
    case unclosedbold
    case unclosedItalic
    case unclosedCode
    case malformedLink

    var errorDescription: String? {
        switch self {
        case .unclosedbold:
            return NSLocalizedString("unclosed_bold_markers", comment: "Unclosed bold markers")
        case .unclosedItalic:
            return NSLocalizedString("unclosed_italic_markers", comment: "Unclosed italic markers")
        case .unclosedCode:
            return NSLocalizedString("unclosed_code_markers", comment: "Unclosed code markers")
        case .malformedLink:
            return NSLocalizedString("malformed_links", comment: "Malformed links")
        }
    }
}
