#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
A Python package to transform emoticons in text to their corresponding meanings.
This is useful for NLP preprocessing where emoticons need to be preserved as meaningful text.
"""

from typing import Dict, List, Union
from nltk.tokenize import TweetTokenizer

# Dictionary mapping emoticons to their meanings
EMOTICON_DICT: Dict[str, str] = {
    ':)': 'Smile',
    ':-)': 'Smile',
    ':-]': 'Smile',
    ':]': 'Smile',
    ':-3': 'Smile',
    ':3': 'Smile',
    ':->': 'Smile',
    ':>': 'Smile',
    '8-)': 'Smile',
    '8)': 'Smile',
    ':-}': 'Smile',
    ':}': 'Smile',
    ':o)': 'Smile',
    ':c)': 'Smile',
    ':^)': 'Smile',
    '=]': 'Smile',
    '=)': 'Smile',
    ':-D': 'Laugh',
    ':D': 'Laugh',
    '8-D': 'Laugh',
    '8D': 'Laugh',
    'x-D': 'Laugh',
    'xD': 'Laugh',
    'X-D': 'Laugh',
    'XD': 'Laugh',
    '=D': 'Laugh',
    '=3': 'Laugh',
    'B^D': 'Laugh',
    ':-))': 'Very Happy',
    ':-(': 'Sad',
    ':(': 'Sad',
    ':-c': 'Sad',
    ':c': 'Sad',
    ':-<': 'Sad',
    ':<': 'Sad',
    ':-[': 'Sad',
    ':[': 'Sad',
    ':-||': 'Angry',
    '>:[': 'Angry',
    ':{': 'Angry',
    ':@': 'Angry',
    '>:(': 'Angry',
    "('_')": 'Crying',
    '(/_;)': 'Crying',
    '(T_T)': 'Crying',
    '(;_;)': 'Crying',
    '(;_;': 'Crying',
    '(;_:)': 'Crying',
    '(;O;)': 'Crying',
    '(:_;)': 'Crying',
    '(ToT)': 'Crying',
    '(Ｔ▽Ｔ)': 'Crying',
    ';_;': 'Crying',
    ';-;': 'Crying',
    ';n;': 'Crying',
    ';;': 'Crying',
    'Q.Q': 'Crying',
    'T.T': 'Crying',
    'TnT': 'Crying',
    'QQ': 'Crying',
    'Q_Q': 'Crying',
    '(ー_ー)!!': 'Annoyed',
    '(-.-)': 'Annoyed',
    '(-_-)': 'Annoyed',
    '(一一)': 'Annoyed',
    '(；一_一)': 'Annoyed',
    '＼(~o~)／': 'Excited',
    '＼(^o^)／': 'Excited',
    '＼(-o-)／': 'Excited',
    'ヽ(^。^)ノ': 'Excited',
    'ヽ(^o^)丿': 'Excited',
    '(*^0^*)': 'Excited',
    ":'-(": 'Crying',
    ":'(": 'Crying',
    ":'-)": 'Tears of Joy',
    ":')": 'Tears of Joy',
    "D-':": 'Horror',
    'D:<': 'Horror',
    'D:': 'Horror',
    'D8': 'Horror',
    'D;': 'Horror',
    'D=': 'Horror',
    'DX': 'Horror',
    ':-O': 'Surprised',
    ':O': 'Surprised',
    ':-o': 'Surprised',
    ':o': 'Surprised',
    ':-0': 'Surprised',
    '8-0': 'Surprised',
    '>:O': 'Surprised',
    '(￣□￣;)': 'Surprised',
    '°o°': 'Surprised',
    '°O°': 'Surprised',
    'o_0': 'Surprised',
    'o.O': 'Surprised',
    '(o.o)': 'Surprised',
    'oO': 'Surprised',
    ':-*': 'Kiss',
    ':*': 'Kiss',
    ':×': 'Kiss',
    ';-)': 'Wink',
    ';)': 'Wink',
    '*-)': 'Wink',
    '*)': 'Wink',
    ';-]': 'Wink',
    ';]': 'Wink',
    ';^)': 'Wink',
    ':-,': 'Wink',
    ';D': 'Wink',
    ':-P': 'Tongue',
    ':P': 'Tongue',
    'X-P': 'Tongue',
    'XP': 'Tongue',
    'x-p': 'Tongue',
    'xp': 'Tongue',
    ':-p': 'Tongue',
    ':p': 'Tongue',
    ':-Þ': 'Tongue',
    ':Þ': 'Tongue',
    ':-þ': 'Tongue',
    ':þ': 'Tongue',
    ':-b': 'Tongue',
    ':b': 'Tongue',
    'd:': 'Tongue',
    '=p': 'Tongue',
    '>:P': 'Tongue',
    ':-/': 'Skeptical',
    ':/': 'Skeptical',
    ':-.': 'Skeptical',
    '>:\\': 'Skeptical',
    '>:/': 'Skeptical',
    ':\\': 'Skeptical',
    '=/': 'Skeptical',
    '=\\': 'Skeptical',
    ':L': 'Skeptical',
    '=L': 'Skeptical',
    ':S': 'Skeptical',
    ':-|': 'Neutral',
    ':|': 'Neutral',
    ':$': 'Embarrassed',
    '://)': 'Embarrassed',
    '://3': 'Embarrassed',
    '(^^ゞ': 'Embarrassed',
    '(^_^;)': 'Embarrassed',
    '(-_-;)': 'Embarrassed',
    '(~_~;)': 'Embarrassed',
    '(・.・;)': 'Embarrassed',
    '(・_・;)': 'Embarrassed',
    '(・・;)^^': 'Embarrassed',
    ';^_^;': 'Embarrassed',
    '(#^.^#)': 'Embarrassed',
    '(^^;)': 'Embarrassed',
    ':-X': 'Sealed Lips',
    ':X': 'Sealed Lips',
    ':-#': 'Sealed Lips',
    ':#': 'Sealed Lips',
    ':-&': 'Sealed Lips',
    ':&': 'Sealed Lips',
    'O:-)': 'Angel',
    'O:)': 'Angel',
    '0:-3': 'Angel',
    '0:3': 'Angel',
    '0:-)': 'Angel',
    '0:)': 'Angel',
    '0;^)': 'Angel',
    '>:-)': 'Devil',
    '>:)': 'Devil',
    '}:-)': 'Devil',
    '}:)': 'Devil',
    '3:-)': 'Devil',
    '3:)': 'Devil',
    '>;)': 'Devil',
    '>:3': 'Devil',
    '>;3': 'Devil',
    ':‑J': 'Tongue in Cheek',
    '#‑)': 'Partied All Night',
    '|;-)': 'Cool',
    '|-O': 'Bored',
    '%-)': 'Confused',
    '%)': 'Confused',
    ':-###..': 'Being Sick',
    ':###.': 'Being Sick',
    '<:-|': 'Dump',
    '(>_<)': 'Troubled',
    '(>_<)>': 'Troubled',
    '((+_+))': 'Troubled',
    '(+o+)': 'Troubled',
    '(°°)': 'Shocked',
    '(°-°)': 'Shocked',
    '(°.°)': 'Shocked',
    '(°_°)': 'Shocked',
    '(°_°>)': 'Shocked',
    '(°レ°)': 'Shocked',
    '^_^': 'Happy',
    '(°o°)': 'Shocked',
    '(^_^)/': 'Wave',
    '(^O^)／': 'Wave',
    '(^o^)／': 'Wave',
    '(^^)/': 'Wave',
    '(-∇-)/': 'Wave',
    '(/-ヮ-)/': 'Wave',
    '(^o^)丿': 'Wave',
    '∩(·ω·)∩': 'Wagging',
    '(·ω·)': 'Wagging',
    '^ω^': 'Wagging',
    '"(-""-)"': 'Annoyed',
    '(ーー゛)': 'Annoyed',
    '(^_^メ)': 'Annoyed',
    '(-_-メ)': 'Annoyed',
    '(~_~メ)': 'Annoyed',
    '(－－〆)': 'Annoyed',
    '(・へ・)': 'Annoyed',
    '(｀´)': 'Annoyed',
    '<`～´>': 'Annoyed',
    '<`ヘ´>': 'Annoyed',
    '(ーー;)': 'Annoyed'
}

def emoticon_fix(input_string: str) -> str:
    """
    Transform emoticons in a string to their corresponding meanings.
    
    Args:
        input_string (str): The input string containing emoticons
        
    Returns:
        str: The string with emoticons replaced by their meanings
        
    Example:
        >>> emoticon_fix('Hello :) World :D')
        'Hello Smile World Laugh'
    """
    if not isinstance(input_string, str):
        raise TypeError("Input must be a string")
        
    tknzr = TweetTokenizer()
    tokens = tknzr.tokenize(input_string)
    
    result = []
    for token in tokens:
        if token in EMOTICON_DICT:
            result.append(EMOTICON_DICT[token])
        else:
            result.append(token)
            
    return ' '.join(result)