import Foundation

/// Constructs approximate English translations for Spanish conjugation forms
/// by combining the verb's English infinitive with person pronouns and tense auxiliaries.
///
/// Not perfect for irregular English verbs (go→went, be→was) but covers the
/// common patterns well enough for a learning context.
public enum EnglishConjugator {

    public static func translate(english: String, tenseId: String, personIndex: Int) -> String {
        let base = english.hasPrefix("to ") ? String(english.dropFirst(3)).trimmingCharacters(in: .whitespaces) : english
        guard !base.isEmpty else { return "" }

        let pronoun = pronoun(for: personIndex)

        switch tenseId {
        // Indicative
        case "ind_presente":
            return "\(pronoun) \(presentForm(base, personIndex: personIndex))"
        case "ind_preterito":
            return "\(pronoun) \(pastForm(base))"
        case "ind_imperfecto":
            return "\(pronoun) used to \(base)"
        case "ind_futuro":
            return "\(pronoun) will \(base)"
        case "ind_perfecto":
            return "\(pronoun) \(haveForm(personIndex)) \(pastParticiple(base))"
        case "ind_pluscuamperfecto":
            return "\(pronoun) had \(pastParticiple(base))"
        case "ind_futuro_perfecto":
            return "\(pronoun) will have \(pastParticiple(base))"
        case "ind_preterito_anterior":
            return "\(pronoun) had \(pastParticiple(base))"

        // Conditional
        case "cond_presente":
            return "\(pronoun) would \(base)"
        case "cond_perfecto":
            return "\(pronoun) would have \(pastParticiple(base))"

        // Subjunctive
        case "subj_presente":
            return "that \(pronoun) \(base)"
        case "subj_imperfecto_1", "subj_imperfecto_2":
            return "that \(pronoun) would \(base)"
        case "subj_perfecto":
            return "that \(pronoun) \(haveForm(personIndex)) \(pastParticiple(base))"
        case "subj_pluscuamperfecto_1", "subj_pluscuamperfecto_2":
            return "that \(pronoun) had \(pastParticiple(base))"
        case "subj_futuro":
            return "that \(pronoun) will \(base)"
        case "subj_futuro_perfecto":
            return "that \(pronoun) will have \(pastParticiple(base))"

        // Imperative
        case "imp_afirmativo":
            return imperativeAffirmative(base, personIndex: personIndex)
        case "imp_negativo":
            return "don't \(base)"

        default:
            return "\(pronoun) \(base)"
        }
    }

    // MARK: - Pronouns

    private static func pronoun(for personIndex: Int) -> String {
        switch personIndex {
        case 0: "I"
        case 1: "you"
        case 2: "he/she"
        case 3: "we"
        case 4: "you all"
        case 5: "they"
        default: ""
        }
    }

    // MARK: - Present tense

    private static func presentForm(_ base: String, personIndex: Int) -> String {
        // 3rd person singular adds -s/-es
        guard personIndex == 2 else { return base }
        let words = base.split(separator: " ")
        guard let first = words.first else { return base }
        let verb = String(first)
        let rest = words.dropFirst().joined(separator: " ")
        let conjugated = addThirdPersonS(verb)
        return rest.isEmpty ? conjugated : "\(conjugated) \(rest)"
    }

    private static func addThirdPersonS(_ verb: String) -> String {
        if verb == "have" { return "has" }
        if verb == "be" { return "is" }
        if verb == "do" { return "does" }
        if verb == "go" { return "goes" }
        if verb.hasSuffix("sh") || verb.hasSuffix("ch") || verb.hasSuffix("x") ||
           verb.hasSuffix("s") || verb.hasSuffix("z") || verb.hasSuffix("o") {
            return verb + "es"
        }
        if verb.hasSuffix("y") && verb.count > 1 {
            let yIndex = verb.index(before: verb.endIndex)
            let beforeY = verb[verb.index(before: yIndex)]
            if !"aeiou".contains(beforeY) {
                return String(verb.dropLast()) + "ies"
            }
        }
        return verb + "s"
    }

    // MARK: - Past tense

    private static func pastForm(_ base: String) -> String {
        // Check common irregulars first
        let words = base.split(separator: " ")
        guard let first = words.first else { return base }
        let verb = String(first).lowercased()
        let rest = words.dropFirst().joined(separator: " ")

        let irregular: String? = commonIrregularPast[verb]
        let past = irregular ?? addEd(String(first))
        return rest.isEmpty ? past : "\(past) \(rest)"
    }

    private static func addEd(_ verb: String) -> String {
        if verb.hasSuffix("e") { return verb + "d" }
        if verb.hasSuffix("y") && verb.count > 1 {
            let beforeY = verb[verb.index(before: verb.endIndex)]
            if !"aeiou".contains(beforeY) {
                return String(verb.dropLast()) + "ied"
            }
        }
        return verb + "ed"
    }

    // MARK: - Past participle

    private static func pastParticiple(_ base: String) -> String {
        let words = base.split(separator: " ")
        guard let first = words.first else { return base }
        let verb = String(first).lowercased()
        let rest = words.dropFirst().joined(separator: " ")

        let irregular: String? = commonIrregularParticiple[verb]
        let participle = irregular ?? addEd(String(first))
        return rest.isEmpty ? participle : "\(participle) \(rest)"
    }

    // MARK: - Gerund

    private static func gerund(_ base: String) -> String {
        let words = base.split(separator: " ")
        guard let first = words.first else { return base }
        let verb = String(first)
        let rest = words.dropFirst().joined(separator: " ")

        let ing: String
        if verb.hasSuffix("ie") {
            ing = String(verb.dropLast(2)) + "ying"
        } else if verb.hasSuffix("e") && !verb.hasSuffix("ee") {
            ing = String(verb.dropLast()) + "ing"
        } else {
            ing = verb + "ing"
        }
        return rest.isEmpty ? ing : "\(ing) \(rest)"
    }

    // MARK: - Auxiliaries

    private static func haveForm(_ personIndex: Int) -> String {
        personIndex == 2 ? "has" : "have"
    }

    private static func beForm(_ personIndex: Int) -> String {
        switch personIndex {
        case 0: "am"
        case 2: "is"
        default: "are"
        }
    }

    // MARK: - Imperative

    private static func imperativeAffirmative(_ base: String, personIndex: Int) -> String {
        switch personIndex {
        case 1, 4: "\(base)!"
        case 3: "let's \(base)!"
        default: "\(base)!"
        }
    }

    // MARK: - Irregular lookups (most common English irregulars)

    private static let commonIrregularPast: [String: String] = [
        "be": "was/were", "have": "had", "do": "did", "go": "went",
        "say": "said", "get": "got", "make": "made", "know": "knew",
        "think": "thought", "take": "took", "come": "came", "see": "saw",
        "want": "wanted", "give": "gave", "tell": "told", "find": "found",
        "put": "put", "leave": "left", "bring": "brought", "begin": "began",
        "keep": "kept", "hold": "held", "write": "wrote", "stand": "stood",
        "hear": "heard", "let": "let", "mean": "meant", "set": "set",
        "meet": "met", "run": "ran", "pay": "paid", "sit": "sat",
        "speak": "spoke", "read": "read", "grow": "grew", "lose": "lost",
        "fall": "fell", "feel": "felt", "cut": "cut", "sell": "sold",
        "drive": "drove", "buy": "bought", "wear": "wore", "choose": "chose",
        "sleep": "slept", "eat": "ate", "drink": "drank", "swim": "swam",
        "fly": "flew", "break": "broke", "sing": "sang", "catch": "caught",
        "send": "sent", "build": "built", "spend": "spent", "win": "won",
        "fight": "fought", "throw": "threw", "teach": "taught", "lead": "led",
        "understand": "understood", "draw": "drew", "ride": "rode",
        "rise": "rose", "shake": "shook", "forget": "forgot",
        "shoot": "shot", "wake": "woke", "bite": "bit", "hide": "hid",
        "lay": "laid", "lie": "lay", "strike": "struck", "hang": "hung",
        "blow": "blew", "dig": "dug", "feed": "fed", "forgive": "forgave",
        "freeze": "froze", "hurt": "hurt", "light": "lit", "shut": "shut",
        "steal": "stole", "stick": "stuck", "sweep": "swept",
        "swing": "swung", "tear": "tore",
    ]

    private static let commonIrregularParticiple: [String: String] = [
        "be": "been", "have": "had", "do": "done", "go": "gone",
        "say": "said", "get": "gotten", "make": "made", "know": "known",
        "think": "thought", "take": "taken", "come": "come", "see": "seen",
        "give": "given", "tell": "told", "find": "found",
        "put": "put", "leave": "left", "bring": "brought", "begin": "begun",
        "keep": "kept", "hold": "held", "write": "written", "stand": "stood",
        "hear": "heard", "let": "let", "mean": "meant", "set": "set",
        "meet": "met", "run": "run", "pay": "paid", "sit": "sat",
        "speak": "spoken", "read": "read", "grow": "grown", "lose": "lost",
        "fall": "fallen", "feel": "felt", "cut": "cut", "sell": "sold",
        "drive": "driven", "buy": "bought", "wear": "worn", "choose": "chosen",
        "sleep": "slept", "eat": "eaten", "drink": "drunk", "swim": "swum",
        "fly": "flown", "break": "broken", "sing": "sung", "catch": "caught",
        "send": "sent", "build": "built", "spend": "spent", "win": "won",
        "fight": "fought", "throw": "thrown", "teach": "taught", "lead": "led",
        "understand": "understood", "draw": "drawn", "ride": "ridden",
        "rise": "risen", "shake": "shaken", "forget": "forgotten",
        "shoot": "shot", "wake": "woken", "bite": "bitten", "hide": "hidden",
        "lay": "laid", "lie": "lain", "strike": "struck", "hang": "hung",
        "blow": "blown", "dig": "dug", "feed": "fed", "forgive": "forgiven",
        "freeze": "frozen", "hurt": "hurt", "light": "lit", "shut": "shut",
        "steal": "stolen", "stick": "stuck", "sweep": "swept",
        "swing": "swung", "tear": "torn",
    ]
}
