# Module 1: Estimation of modal weight distribution p(m)
def estimate_modal_weights(interaction_logs):
    """
    Estimate p(T), p(A), p(V) from effective attention duration per modality.
    Input: list of logs, each containing t_T, t_A, t_V (in seconds)
    Output: dict with keys 'T', 'A', 'V'
    """
    N = len(interaction_logs)
    sum_weights = {'T': 0.0, 'A': 0.0, 'V': 0.0}
    for log in interaction_logs:
        total = log['t_T'] + log['t_A'] + log['t_V']
        sum_weights['T'] += log['t_T'] / total
        sum_weights['A'] += log['t_A'] / total
        sum_weights['V'] += log['t_V'] / total
    return {m: sum_weights[m] / N for m in ['T', 'A', 'V']}

# Module 2: Multimodal situation vector construction
def encode_situation(text_description, audio_features, image_features, p_weights):
    """
    Encode multimodal situation into a 384-dim semantic vector.
    p_weights: dict with keys 'T','A','V' (sum to 1)
    """
    text_vec = SentenceBERT.encode(text_description)          # 384-dim
    audio_vec = Wav2Vec2.project(audio_features)              # projected to 384-dim
    image_vec = CLIP.project(image_features)                  # projected to 384-dim
    return (p_weights['T'] * text_vec +
            p_weights['A'] * audio_vec +
            p_weights['V'] * image_vec)

# Module 3: Student profile vector construction
def build_student_profile(pre_test_scores, vark_onehot, prior_grades):
    """
    pre_test_scores: 4-dim list [knowledge, critical, innovation, collaboration]
    vark_onehot: 4-dim one-hot encoding (V,A,R,K)
    prior_grades: 2-dim list [STEM_avg, humanities_avg]
    Returns: 10-dim concatenated vector
    """
    import numpy as np
    return np.concatenate([pre_test_scores, vark_onehot, prior_grades])

# Module 4: Situation–student matching score (cosine similarity)
def compute_match_score(situation_vec, profile_vec, projection_matrix):
    """
    situation_vec: 384-dim
    profile_vec: 10-dim
    projection_matrix: 10 x 384, learned from pilot data
    Returns: cosine similarity in [0,1]
    """
    import numpy as np
    proj_sit = np.dot(projection_matrix, situation_vec)       # reduce to 10-dim
    norm_proj = np.linalg.norm(proj_sit)
    norm_prof = np.linalg.norm(profile_vec)
    if norm_proj == 0 or norm_prof == 0:
        return 0.0
    return np.dot(proj_sit, profile_vec) / (norm_proj * norm_prof)

# Module 5: Teaching strategy selection (Softmax with temperature)
def select_strategy(cognitive_state, dialogue_history, tau=0.8, fallback_threshold=0.5):
    """
    cognitive_state: current cognitive status vector
    dialogue_history: list of previous interaction turns
    tau: temperature for Softmax
    fallback_threshold: if max score < threshold, return 'Q' (questioning)
    Returns: selected strategy among ['Q','S','C','D','R']
    """
    strategies = ['Q', 'S', 'C', 'D', 'R']   # Question, Scaffold, Case, Discuss, Reflect
    scores = [compute_match_score(cognitive_state, s, dialogue_history) for s in strategies]
    import numpy as np
    exp_scores = np.exp(np.array(scores) / tau)
    probs = exp_scores / np.sum(exp_scores)
    if max(scores) < fallback_threshold:
        return 'Q'   # fallback to questioning
    return strategies[np.argmax(probs)]

# Module 6: Single‑round reward computation (weighted linear combination)
def compute_reward(delta_vector, task_type, weight_map):
    """
    delta_vector: [ΔK_know, ΔK_crit, ΔK_innov, ΔK_collab] all in [0,1]
    task_type: one of {'scenario', 'interaction', 'evaluation'}
    weight_map: dict mapping task_type to 4-dim weight list (sum=1)
    Returns: scalar reward
    """
    weights = weight_map[task_type]   # e.g., for 'scenario': [0.167, 0.167, 0.5, 0.167]
    import numpy as np
    return np.dot(weights, delta_vector)

# Module 7: Cognitive state update with learning rate α
def update_cognitive_state(K_old, intervention, feedback, alpha=0.28):
    """
    K_old: previous cognitive state vector
    intervention: MLLM's teaching action in current round
    feedback: student's response
    alpha: learning rate (empirically calibrated to 0.28)
    Returns: updated cognitive state vector
    """
    delta = state_transition_function(K_old, intervention, feedback)   # compute single‑round change
    return K_old + alpha * delta

# Helper function (conceptual) – actual implementation depends on specific task logic
def state_transition_function(K, intervention, feedback):
    """
    Placeholder for the domain‑specific transition model.
    In practice, this computes the immediate cognitive gain based on
    the intervention type and student feedback.
    """
    # Implementation details omitted for brevity; see Section 3.1.2 for theoretical formulation.
    pass