"""
Thai Backchannel Classifier
Usage: from thai_backchannel import is_backchannel
"""

import re
import pickle
import numpy as np
import os

_MODEL = None
_DIR = os.path.dirname(os.path.abspath(__file__))


def extract_features(text):
    """Extract features from Thai text"""
    text = text.strip()
    char_len = len(text)
    thai_chars = len(re.findall(r'[\u0E00-\u0E7F]', text))
    words = text.split()
    word_count = len(words)
    
    has_krab = 1 if re.search(r'ครับ|คับ', text) else 0
    has_ka = 1 if re.search(r'ค่ะ|คะ|ค่า', text) else 0
    has_ja = 1 if re.search(r'จ้ะ|จ้า|จ๊ะ', text) else 0
    has_hmm = 1 if re.search(r'อืม|อือ|อื้อ|อื้ม|อึม|อุ้ม', text) else 0
    has_oh = 1 if re.search(r'อ๋อ|เออ|เอ่อ|อ่า|อ้า|อ๊า+', text) else 0
    has_aha = 1 if re.search(r'อ่าฮะ|อาฮะ|อาหะ|อ้าฮะ', text) else 0
    has_hello = 1 if 'ฮัลโหล' in text else 0
    has_chai = 1 if re.search(r'ใช่|ช่าย', text) else 0
    has_jing = 1 if 'จริง' in text else 0
    has_thuk = 1 if 'ถูก' in text else 0
    has_ok = 1 if re.search(r'โอเค|เค$|เคร$', text) else 0
    has_naenon = 1 if 'แน่นอน' in text else 0
    has_wama = 1 if 'ว่ามา' in text else 0
    has_question = 1 if re.search(r'ไหม|อะไร|ที่ไหน|เมื่อไหร่|ยังไง|ทำไม|กี่|เท่าไหร่', text) else 0
    has_negation = 1 if re.search(r'ไม่|ยัง(?!ไง)', text) else 0
    has_request = 1 if re.search(r'ขอ|ช่วย|อยาก|ต้องการ', text) else 0
    has_continuation = 1 if re.search(r'แต่|แล้ว|แล้วก็|งั้น(?!เหรอ)', text) else 0
    has_repeat = 1 if 'ๆ' in text else 0
    particle_ratio = (has_krab + has_ka + has_ja) / max(word_count, 1)
    
    remaining = text
    for pattern in ['ครับ', 'คับ', 'ค่ะ', 'คะ', 'ค่า', 'จ้ะ', 'จ้า', 'ผม',
                    'อืม', 'อือ', 'อื้อ', 'อื้ม', 'อึม',
                    'เออ', 'เอ่อ', 'อ่า', 'อ้า', 'อ่าฮะ', 'อาฮะ', 'อ้าฮะ',
                    'อ๋อ', 'ใช่', 'ช่าย', 'จริง', 'ด้วย', 'ถูก', 'โอเค', 'เค', 'เคร',
                    'แน่นอน', 'เหรอ', 'หรอ', 'งั้น', 'ได้', 'อ่ะ', 'เอ๊ะ', 'ว่ามา', 'เลย',
                    'อาหะ', 'อือหึ', 'อือฮึ', 'ฮัลโหล', 'ๆ', ' ']:
        remaining = remaining.replace(pattern, '')
    remaining = re.sub(r'อ[๊้]า+', '', remaining)
    remaining_len = len(remaining)
    remaining_ratio = remaining_len / max(char_len, 1)
    
    return np.array([
        char_len, thai_chars, word_count,
        has_krab, has_ka, has_ja,
        has_hmm, has_oh, has_aha, has_hello,
        has_chai, has_jing, has_thuk, has_ok, has_naenon,
        has_question, has_negation, has_request,
        has_continuation, has_repeat,
        particle_ratio, remaining_len, remaining_ratio,
        has_wama,
    ])


def _load_model():
    global _MODEL
    if _MODEL is None:
        import warnings
        import sklearn
        pkl_path = os.path.join(_DIR, 'backchannel_model.pkl')
        try:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                with open(pkl_path, 'rb') as f:
                    data = pickle.load(f)
                _MODEL = data['model']
                # verify it works with current sklearn
                test_features = extract_features("ครับ").reshape(1, -1)
                _MODEL.predict(test_features)
        except Exception:
            # retrain if pkl is incompatible
            _MODEL = _retrain_model(pkl_path)
    return _MODEL


def _retrain_model(pkl_path):
    """Retrain model from inline data when pkl is incompatible with current sklearn"""
    import random
    from sklearn.ensemble import GradientBoostingClassifier
    
    # import training data from train module
    import importlib.util
    train_path = os.path.join(os.path.dirname(_DIR), 'train.py')
    if os.path.exists(train_path):
        spec = importlib.util.spec_from_file_location("train_module", train_path)
        train_mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(train_mod)
        pos_examples = train_mod.augment_backchannels(train_mod.BACKCHANNELS)
        neg_examples = list(train_mod.REAL_RESPONSES)
    else:
        raise RuntimeError("Cannot retrain: train.py not found alongside package")
    
    random.seed(42)
    X_pos = np.array([extract_features(t) for t in pos_examples])
    X_neg = np.array([extract_features(t) for t in neg_examples])
    X = np.vstack([X_pos, X_neg])
    y = np.array([1] * len(pos_examples) + [0] * len(neg_examples))
    indices = list(range(len(X)))
    random.shuffle(indices)
    X = X[indices]
    y = y[indices]
    
    model = GradientBoostingClassifier(n_estimators=100, max_depth=4, random_state=42)
    model.fit(X, y)
    
    # save updated pkl
    try:
        with open(pkl_path, 'wb') as f:
            pickle.dump({'model': model, 'feature_names': [], 'backchannels': []}, f)
    except Exception:
        pass  # read-only install, just use in-memory
    
    return model


def is_backchannel(text: str, threshold: float = 0.5) -> tuple:
    """
    Detect if text is a backchannel.
    
    Returns: (is_backchannel: bool, confidence: float)
    """
    if not text or not text.strip():
        return False, 0.0
    
    model = _load_model()
    features = extract_features(text).reshape(1, -1)
    prob = model.predict_proba(features)[0]
    bc_prob = prob[1]  # probability of backchannel class
    return bc_prob >= threshold, float(bc_prob)


if __name__ == '__main__':
    import sys
    if len(sys.argv) > 1:
        text = ' '.join(sys.argv[1:])
        is_bc, conf = is_backchannel(text)
        print(f"'{text}' -> {'BACKCHANNEL' if is_bc else 'REAL RESPONSE'} (confidence: {conf:.4f})")
    else:
        # Interactive mode
        print("Thai Backchannel Detector - type text to classify (ctrl+c to exit)")
        while True:
            try:
                text = input("> ")
                is_bc, conf = is_backchannel(text)
                label = "BACKCHANNEL" if is_bc else "REAL RESPONSE"
                print(f"  -> {label} (confidence: {conf:.4f})")
            except (KeyboardInterrupt, EOFError):
                break
