use crate::dict::Dictionary;

pub fn score_candidate(
    word_idx: usize,
    dict: &Dictionary,
    used_words: &[bool],
    placed_texts: &[String],
) -> f64 {
    if used_words[word_idx] {
        return -1.0;
    }

    let word = dict.get(word_idx);
    let text = &word.text;
    let mut score = word.frequency;

    // reject words that are too similar to already-placed words
    for placed in placed_texts {
        if is_related(text, placed) {
            return -1.0;
        }
    }

    // bonus for letter variety
    let bytes = text.as_bytes();
    let mut seen = [false; 26];
    let mut unique = 0;
    for &b in bytes {
        let idx = (b - b'A') as usize;
        if !seen[idx] {
            seen[idx] = true;
            unique += 1;
        }
    }
    let variety = unique as f64 / bytes.len() as f64;
    score += variety * 0.1;

    // bonus for common letters
    let common = b"ETAOINSHRDLU";
    let common_count = bytes.iter().filter(|b| common.contains(b)).count();
    let common_ratio = common_count as f64 / bytes.len() as f64;
    score += common_ratio * 0.05;

    score
}

pub fn is_related(a: &str, b: &str) -> bool {
    // one is a prefix of the other (SEAL / SEALS, RUN / RUNNING)
    if a.len() >= 3 && b.len() >= 3 {
        let (short, long) = if a.len() <= b.len() { (a, b) } else { (b, a) };
        if long.starts_with(short) {
            let suffix = &long[short.len()..];
            // common inflection suffixes
            if matches!(suffix, "S" | "ES" | "ED" | "ER" | "ING" | "LY" | "TION" | "NESS" | "MENT" | "ABLE" | "ISH" | "IST" | "IZE") {
                return true;
            }
        }
        // handle e-dropping: MAKE/MAKING, BAKE/BAKING
        if short.len() >= 4 && long.ends_with("ING") {
            let stem = &long[..long.len() - 3];
            if short.len() == stem.len() + 1 && short.starts_with(stem) && short.ends_with('E') {
                return true;
            }
        }
        // consonant doubling: RUN/RUNNING, SIT/SITTING
        if long.ends_with("ING") && long.len() >= 6 {
            let before_ing = &long[..long.len() - 3];
            let bb = before_ing.as_bytes();
            if bb.len() >= 4 && bb[bb.len() - 1] == bb[bb.len() - 2] {
                let stem = &before_ing[..before_ing.len() - 1];
                if short == stem {
                    return true;
                }
            }
        }
        // also ED doubling: STOP/STOPPED
        if long.ends_with("ED") && long.len() >= 5 {
            let before_ed = &long[..long.len() - 2];
            let bb = before_ed.as_bytes();
            if bb.len() >= 4 && bb[bb.len() - 1] == bb[bb.len() - 2] {
                let stem = &before_ed[..before_ed.len() - 1];
                if short == stem {
                    return true;
                }
            }
        }
    }
    false
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn related_words() {
        assert!(is_related("SEAL", "SEALS"));
        assert!(is_related("RUN", "RUNNING"));
        assert!(is_related("MAKE", "MAKING"));
        assert!(is_related("PLAY", "PLAYED"));
        assert!(is_related("PLAY", "PLAYER"));
        assert!(is_related("QUICK", "QUICKLY"));
        assert!(!is_related("CAT", "DOG"));
        assert!(!is_related("SEA", "SEAL"));
        assert!(!is_related("THE", "THEM"));
    }
}
