import APIClient
import Foundation

public extension InteractiveTextFormatter {
    static let validMentionChars = CharacterSet.alphanumerics.union(.init(charactersIn: "_"))

    static func replacePendingMention<T: UserMention>(
        from text: String,
        for user: SimpleProfile,
        mentions: inout [T],
        createMention: (Int, Int, String, String?) -> T
    ) -> String {
        guard let result = prepareMentionReplacement(from: text, for: user) else { return text }

        let mention = createMention(
            result.startIndex,
            result.endIndex,
            user.handle,
            user.displayName
        )
        mentions.append(mention)

        return result.updatedText
    }

    static func isValidMention<T: UserMention>(_ mention: T, in text: String) -> Bool {
        guard let actualText = substring(from: text, start: mention.start, end: mention.end) else { return false }
        let expectedText = mention.displayName?.isEmpty == false ? mention.displayName! : "@\(mention.handle)"
        return actualText == expectedText
    }

    /// Finds the @mention currently being typed at the end of text
    static func extractCurrentMention(from text: String) -> String? {
        guard let atIndex = text.lastIndex(of: "@") else { return nil }

        let mentionStart = text.index(after: atIndex)
        let suffix = text[mentionStart...]

        let mention = suffix.prefix {
            $0.unicodeScalars.allSatisfy { validMentionChars.contains($0) }
        }
        if !text.hasSuffix("@\(mention)") {
            return nil
        }
        return String(mention)
    }

    /// Prepares mention replacement - returns updated text and position info
    static func prepareMentionReplacement(
        from text: String,
        for user: SimpleProfile
    ) -> (updatedText: String, startIndex: Int, endIndex: Int)? {
        guard let atIndex = text.lastIndex(of: "@") else { return nil }

        let mentionStart = text.index(after: atIndex)
        let suffix = text[mentionStart...]

        var updatedText = text
        let rangeToReplace = atIndex ..< text.index(mentionStart, offsetBy: suffix.count)
        let mentionPosition = text.distance(from: text.startIndex, to: rangeToReplace.lowerBound)

        let replacementText = user.displayName.isEmpty ? "@\(user.handle)" : user.displayName
        updatedText.replaceSubrange(rangeToReplace, with: replacementText)

        let mentionEnd = mentionPosition + replacementText.count
        return (updatedText, mentionPosition, mentionEnd)
    }

    static func substring(from text: String, start: Int, end: Int) -> String? {
        guard start >= 0, end <= text.count, start < end else { return nil }
        let startIndex = text.index(text.startIndex, offsetBy: start)
        let endIndex = text.index(text.startIndex, offsetBy: end)
        return String(text[startIndex ..< endIndex])
    }
}
