import Foundation

/// Pure logic for the Complete the Sentence quiz type.
///
/// Given a `VocabCard` with example sentences, the engine determines whether a
/// blankable question can be produced and builds the `Question` used by the UI.
/// No SwiftUI dependency — exists in SharedModels so it can be unit-tested in
/// isolation and reused by other surfaces.
public struct SentenceQuizEngine {

    public struct Question: Equatable, Sendable {
        public let sentenceES: String
        public let sentenceEN: String
        /// The exact substring in `sentenceES` that was blanked (original casing preserved).
        public let blankWord: String
        /// `sentenceES` with `blankWord` replaced by a visible blank marker.
        public let displayTemplate: String
        /// Index into the card's `examplesES` that this question was built from.
        public let exampleIndex: Int

        public init(sentenceES: String, sentenceEN: String, blankWord: String, displayTemplate: String, exampleIndex: Int) {
            self.sentenceES = sentenceES
            self.sentenceEN = sentenceEN
            self.blankWord = blankWord
            self.displayTemplate = displayTemplate
            self.exampleIndex = exampleIndex
        }
    }

    /// Marker string substituted into `displayTemplate` in place of the blank word.
    public static let blankMarker = "_____"

    /// True when the card has at least one example sentence where a blank can be determined,
    /// either via a stored `examplesBlanks` entry or by substring-matching `card.front`.
    public static func hasValidSentence(for card: VocabCard) -> Bool {
        guard !card.examplesES.isEmpty else { return false }
        for i in card.examplesES.indices {
            if isBlankResolvable(card: card, exampleIndex: i) {
                return true
            }
        }
        return false
    }

    /// Returns the set of example indices that can produce a valid blank.
    public static func resolvableIndices(for card: VocabCard) -> [Int] {
        card.examplesES.indices.filter { isBlankResolvable(card: card, exampleIndex: $0) }
    }

    /// Builds a question from the card by picking a random resolvable example.
    /// Returns nil if no example qualifies.
    public static func buildQuestion(for card: VocabCard) -> Question? {
        let candidates = resolvableIndices(for: card)
        guard let pick = candidates.randomElement() else { return nil }
        return buildQuestion(for: card, exampleIndex: pick)
    }

    /// Deterministic variant — builds a question from a specific example index.
    /// Returns nil if that example doesn't contain a resolvable blank.
    public static func buildQuestion(for card: VocabCard, exampleIndex: Int) -> Question? {
        guard exampleIndex >= 0, exampleIndex < card.examplesES.count else { return nil }
        let sentence = card.examplesES[exampleIndex]
        guard sentence.split(separator: " ").count >= minimumWordCount else { return nil }
        let sentenceEN = exampleIndex < card.examplesEN.count ? card.examplesEN[exampleIndex] : ""

        let storedBlank = exampleIndex < card.examplesBlanks.count ? card.examplesBlanks[exampleIndex] : ""

        // Prefer the stored blank if present and actually appears in the sentence.
        if !storedBlank.isEmpty, let range = sentence.range(of: storedBlank, options: .caseInsensitive) {
            return makeQuestion(sentence: sentence, sentenceEN: sentenceEN, range: range, exampleIndex: exampleIndex)
        }

        // Fall back to substring match on card.front.
        if !card.front.isEmpty, let range = sentence.range(of: card.front, options: .caseInsensitive) {
            return makeQuestion(sentence: sentence, sentenceEN: sentenceEN, range: range, exampleIndex: exampleIndex)
        }

        return nil
    }

    // MARK: - Private

    /// Minimum number of whitespace-separated tokens for an example to count as
    /// a real sentence (filters out phonetic glosses like "discutir(dees-koo-teer)").
    public static let minimumWordCount = 4

    private static func isBlankResolvable(card: VocabCard, exampleIndex: Int) -> Bool {
        let sentence = card.examplesES[exampleIndex]
        guard sentence.split(separator: " ").count >= minimumWordCount else { return false }
        let storedBlank = exampleIndex < card.examplesBlanks.count ? card.examplesBlanks[exampleIndex] : ""
        if !storedBlank.isEmpty, sentence.range(of: storedBlank, options: .caseInsensitive) != nil {
            return true
        }
        if !card.front.isEmpty, sentence.range(of: card.front, options: .caseInsensitive) != nil {
            return true
        }
        return false
    }

    private static func makeQuestion(sentence: String, sentenceEN: String, range: Range<String.Index>, exampleIndex: Int) -> Question {
        let blankWord = String(sentence[range])
        var template = sentence
        template.replaceSubrange(range, with: blankMarker)
        return Question(
            sentenceES: sentence,
            sentenceEN: sentenceEN,
            blankWord: blankWord,
            displayTemplate: template,
            exampleIndex: exampleIndex
        )
    }
}
