//
//  InlineText.swift
//  ThemeKit
//  Created by İsa Mercan on 23.06.2026.
//

import SwiftUI

/// Atom. Body text with tappable inline links. Improves on the reference
/// UnderlineText by using AttributedString + openURL routing instead of manual
/// NSRange math.
public struct InlineText: View {
    @Environment(\.theme) private var theme

    private let text: String
    private let links: [(substring: String, action: () -> Void)]

    // Appearance/config — mutated only through the modifiers below (R2).
    private var baseColor: Color? = nil
    private var style: TextStyle = .bodySm400

    public init(_ text: String, links: [(substring: String, action: () -> Void)] = []) {   // R1
        self.text = text
        self.links = links
    }

    public var body: some View {
        Text(attributed)
            .environment(\.openURL, OpenURLAction { url in
                guard url.scheme == "inline",
                      let index = Int(url.absoluteString.replacingOccurrences(of: "inline:", with: "")),
                      links.indices.contains(index) else { return .systemAction }
                links[index].action()
                return .handled
            })
    }

    private var attributed: AttributedString {
        var string = AttributedString(text)
        string.font = style.font
        string.foregroundColor = baseColor ?? theme.text(.textSecondary)
        for (index, link) in links.enumerated() {
            if let range = string.range(of: link.substring) {
                string[range].foregroundColor = theme.text(.textHero)
                string[range].underlineStyle = .single
                string[range].link = URL(string: "inline:\(index)")
            }
        }
        return string
    }
}

// MARK: - Modifiers (R2 copy-on-write · R5 standard vocabulary)

public extension InlineText {
    /// Base text color (defaults to the theme's secondary text color).
    func color(_ color: Color?) -> Self { copy { $0.baseColor = color } }

    /// Typography token for the body text. Named `inlineStyle` so it doesn't
    /// shadow the kit-wide `.textStyle(_:)` view modifier.
    func inlineStyle(_ style: TextStyle) -> Self { copy { $0.style = style } }

    private func copy(_ mutate: (inout Self) -> Void) -> Self {   // R2 — single mutation point
        var c = self
        mutate(&c)
        return c
    }
}

#Preview {
    InlineText("By continuing you accept the Terms and the Privacy Policy.",
               links: [("Terms", { print("terms") }), ("Privacy Policy", { print("privacy") })])
        .padding()
}
