package com.tiedup.remake.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Analyzes word structure to preserve rhythm in gagged speech.
 */
public class SyllableAnalyzer {

    private static final Set<Character> VOWELS = Set.of(
        'a',
        'e',
        'i',
        'o',
        'u',
        'y'
    );

    /**
     * Count the number of syllables in a word.
     *
     * @param word The word to analyze
     * @return The number of syllables (minimum 1)
     */
    public static int countSyllables(String word) {
        if (word == null || word.isEmpty()) {
            return 0;
        }

        String cleanWord = word.toLowerCase().replaceAll("[^a-z]", "");
        if (cleanWord.isEmpty()) {
            return 1;
        }

        int count = 0;
        boolean prevVowel = false;

        for (int i = 0; i < cleanWord.length(); i++) {
            boolean isVowel = VOWELS.contains(cleanWord.charAt(i));

            if (isVowel && !prevVowel) {
                count++;
            }
            prevVowel = isVowel;
        }

        // Handle silent 'e' at end (common in English/French)
        if (cleanWord.length() > 2 && cleanWord.endsWith("e") && count > 1) {
            char beforeE = cleanWord.charAt(cleanWord.length() - 2);
            // Silent 'e' after consonant
            if (!VOWELS.contains(beforeE) && !cleanWord.endsWith("le")) {
                count--;
            }
        }

        return Math.max(1, count);
    }

    /**
     * Split a word into approximate syllables.
     * This is a simplified algorithm that works for most Western languages.
     *
     * @param word The word to split
     * @return List of syllables
     */
    public static List<String> splitIntoSyllables(String word) {
        List<String> syllables = new ArrayList<>();

        if (word == null || word.isEmpty()) {
            return syllables;
        }

        // Preserve original case and non-letter chars
        StringBuilder current = new StringBuilder();
        boolean prevVowel = false;
        int vowelGroups = 0;

        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            char lower = Character.toLowerCase(c);
            boolean isVowel = VOWELS.contains(lower);
            boolean isLetter = Character.isLetter(c);

            if (!isLetter) {
                // Non-letter characters stick with current syllable
                current.append(c);
                continue;
            }

            // Starting a new vowel group after consonants = potential syllable break
            if (
                isVowel && !prevVowel && vowelGroups > 0 && current.length() > 0
            ) {
                // Check if we should split before this vowel
                // Split if we have at least 2 consonants between vowels
                int consonantCount = countTrailingConsonants(
                    current.toString()
                );
                if (consonantCount >= 2) {
                    // Keep one consonant with previous syllable, rest go with new
                    String syllable = current.substring(
                        0,
                        current.length() - consonantCount + 1
                    );
                    String carry = current.substring(
                        current.length() - consonantCount + 1
                    );
                    if (!syllable.isEmpty()) {
                        syllables.add(syllable);
                    }
                    current = new StringBuilder(carry);
                } else if (consonantCount == 1 && current.length() > 1) {
                    // Single consonant goes with new syllable
                    String syllable = current.substring(
                        0,
                        current.length() - 1
                    );
                    String carry = current.substring(current.length() - 1);
                    if (!syllable.isEmpty()) {
                        syllables.add(syllable);
                    }
                    current = new StringBuilder(carry);
                }
            }

            current.append(c);

            if (isVowel && !prevVowel) {
                vowelGroups++;
            }
            prevVowel = isVowel;
        }

        // Add remaining
        if (current.length() > 0) {
            syllables.add(current.toString());
        }

        // If we somehow got no syllables, return the whole word
        if (syllables.isEmpty()) {
            syllables.add(word);
        }

        return syllables;
    }

    /**
     * Count trailing consonants in a string.
     */
    private static int countTrailingConsonants(String s) {
        int count = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            char c = Character.toLowerCase(s.charAt(i));
            if (Character.isLetter(c) && !VOWELS.contains(c)) {
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    /**
     * Check if a syllable position is typically stressed.
     * Simple heuristic: first syllable and syllables with long vowels.
     *
     * @param syllable The syllable content
     * @param position Position in word (0-indexed)
     * @param total    Total number of syllables
     * @return true if likely stressed
     */
    public static boolean isStressedSyllable(
        String syllable,
        int position,
        int total
    ) {
        // First syllable is often stressed in English/Germanic
        if (position == 0) {
            return true;
        }

        // Last syllable in short words
        if (total <= 2 && position == total - 1) {
            return true;
        }

        // Syllables with double vowels or long vowels tend to be stressed
        String lower = syllable.toLowerCase();
        if (
            lower.contains("aa") ||
            lower.contains("ee") ||
            lower.contains("oo") ||
            lower.contains("ii") ||
            lower.contains("uu") ||
            lower.contains("ou") ||
            lower.contains("ai") ||
            lower.contains("ei")
        ) {
            return true;
        }

        return false;
    }

    /**
     * Get the primary vowel of a syllable.
     *
     * @param syllable The syllable to analyze
     * @return The primary vowel character, or 'a' as default
     */
    public static char getPrimaryVowel(String syllable) {
        if (syllable == null || syllable.isEmpty()) {
            return 'a';
        }

        for (char c : syllable.toCharArray()) {
            if (VOWELS.contains(Character.toLowerCase(c))) {
                return Character.toLowerCase(c);
            }
        }

        return 'a';
    }
}
