"""
Human Feel Engine for AbletonMCP-AI
T040-T050: Humanización y dinámicas
"""
import random
from typing import List, Dict, Any

class HumanFeelEngine:
    """
    T040-T050: Engine de humanización y dinámica.
    Aplica variaciones de timing, velocity y groove a patrones MIDI.
    """

    def __init__(self, seed: int = 42):
        self.rng = random.Random(seed)
        self._groove_templates = {
            'straight': {'swing': 0.0, 'humanize': 0.0},
            'shuffle': {'swing': 0.33, 'humanize': 0.02},
            'triplet': {'swing': 0.66, 'humanize': 0.03},
            'latin': {'swing': 0.25, 'humanize': 0.04},
        }

    def apply_timing_variation(self, notes: List[Dict], amount_ms: float = 5.0) -> List[Dict]:
        """T040: Micro-offsets de timing (-5ms a +5ms)."""
        result = []
        for note in notes:
            offset = self.rng.uniform(-amount_ms, amount_ms) / 1000.0
            new_note = dict(note)
            new_note['start'] = note.get('start', 0) + offset
            result.append(new_note)
        return result

    def apply_velocity_humanize(self, notes: List[Dict], variance: float = 0.05) -> List[Dict]:
        """T041: Humanización de velocity (±5% variación)."""
        result = []
        for note in notes:
            vel = note.get('velocity', 100)
            variation = self.rng.uniform(-variance, variance)
            new_vel = int(vel * (1 + variation))
            new_vel = max(1, min(127, new_vel))
            new_note = dict(note)
            new_note['velocity'] = new_vel
            result.append(new_note)
        return result

    def apply_note_skip_probability(self, notes: List[Dict], prob: float = 0.02) -> List[Dict]:
        """T042: Probabilidad de skip nota (2% ghost notes)."""
        result = []
        for note in notes:
            if self.rng.random() > prob:
                result.append(note)
        return result

    def apply_groove(self, notes: List[Dict], style: str = 'shuffle', amount: float = 0.5) -> List[Dict]:
        """T044-T046: Aplica groove template."""
        template = self._groove_templates.get(style, self._groove_templates['straight'])
        swing = template['swing'] * amount

        result = []
        for note in notes:
            start = note.get('start', 0)
            beat_pos = start % 1.0
            if 0.4 < beat_pos < 0.6:
                delay = swing * 0.1
                new_note = dict(note)
                new_note['start'] = start + delay
                result.append(new_note)
            else:
                result.append(note)
        return result

    def apply_section_dynamics(self, notes: List[Dict], section: str) -> List[Dict]:
        """T047-T050: Dinámica por sección (intro 70%, drop 100%, etc)."""
        section_scales = {
            'intro': 0.70,
            'build': 0.85,
            'drop': 1.00,
            'break': 0.75,
            'outro': 0.60,
        }
        scale = section_scales.get(section.lower(), 1.0)

        result = []
        for note in notes:
            vel = note.get('velocity', 100)
            new_vel = int(vel * scale)
            new_vel = max(1, min(127, new_vel))
            new_note = dict(note)
            new_note['velocity'] = new_vel
            result.append(new_note)
        return result

    def process_notes(self, notes: List[Dict], section: str = 'drop',
                      humanize: bool = True, groove_style: str = 'shuffle') -> List[Dict]:
        """Procesamiento completo con todos los efectos."""
        result = list(notes)
        if humanize:
            result = self.apply_timing_variation(result)
            result = self.apply_velocity_humanize(result)
            result = self.apply_note_skip_probability(result)
        result = self.apply_groove(result, groove_style)
        result = self.apply_section_dynamics(result, section)
        return result
