"""Text to viseme conversion module."""
import re
from .config import KOREAN_PHONEME_MAP, VISEME_SET


def decompose_korean_char(char: str) -> tuple[str, str, str]:
    """
    Decompose a Korean character into its components.

    Returns: (initial consonant, vowel, final consonant)
    """
    if not char or not '\uac00' <= char <= '\ud7a3':
        return ('', '', '')

    code = ord(char) - 0xAC00

    # Korean has 19 initial consonants, 21 vowels, 28 final consonants (including none)
    initial_idx = code // (21 * 28)
    vowel_idx = (code % (21 * 28)) // 28
    final_idx = code % 28

    initials = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ"
    vowels = "ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ"
    finals = " ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ"

    return (
        initials[initial_idx],
        vowels[vowel_idx],
        finals[final_idx].strip()
    )


def korean_text_to_visemes(text: str) -> list[dict]:
    """
    Convert Korean text to a sequence of visemes with timing hints.

    Returns: List of dicts with 'viseme', 'duration', 'char' keys
    """
    result = []

    for char in text:
        if '\uac00' <= char <= '\ud7a3':  # Korean syllable
            initial, vowel, final = decompose_korean_char(char)

            # Initial consonant (short)
            if initial and initial != 'ㅇ':
                viseme = KOREAN_PHONEME_MAP.get(initial, 'rest')
                result.append({
                    'viseme': viseme,
                    'duration': 0.05,
                    'char': initial
                })

            # Vowel (main mouth shape, longer)
            if vowel:
                viseme = KOREAN_PHONEME_MAP.get(vowel, 'A')
                result.append({
                    'viseme': viseme,
                    'duration': 0.15,
                    'char': vowel
                })

            # Final consonant (short)
            if final:
                viseme = KOREAN_PHONEME_MAP.get(final, 'rest')
                result.append({
                    'viseme': viseme,
                    'duration': 0.05,
                    'char': final
                })

        elif char.isalpha():  # English/alphabet
            char_lower = char.lower()
            viseme_map = {
                'a': 'A', 'e': 'E', 'i': 'I', 'o': 'O', 'u': 'U',
                'b': 'M', 'm': 'M', 'p': 'M',
                'f': 'F', 'v': 'F',
                'l': 'L', 'r': 'L', 'd': 'L', 't': 'L', 'n': 'L',
                's': 'C', 'z': 'C', 'c': 'C', 'j': 'C',
                'w': 'W',
            }
            viseme = viseme_map.get(char_lower, 'rest')
            result.append({
                'viseme': viseme,
                'duration': 0.1,
                'char': char
            })

        elif char in ' \t\n':  # Whitespace = pause
            result.append({
                'viseme': 'rest',
                'duration': 0.1,
                'char': ' '
            })

        elif char in '.,!?':  # Punctuation = longer pause
            result.append({
                'viseme': 'rest',
                'duration': 0.3,
                'char': char
            })

    return result


def viseme_sequence_to_frames(
    viseme_sequence: list[dict],
    fps: int = 24
) -> list[str]:
    """
    Convert viseme sequence with durations to frame-by-frame viseme list.

    Args:
        viseme_sequence: Output from korean_text_to_visemes
        fps: Frames per second

    Returns:
        List of viseme codes, one per frame
    """
    frames = []

    for item in viseme_sequence:
        num_frames = max(1, int(item['duration'] * fps))
        frames.extend([item['viseme']] * num_frames)

    return frames


def get_viseme_info(viseme: str) -> str:
    """Get the description for a viseme code."""
    return VISEME_SET.get(viseme, "Unknown viseme")
