"""Waveform peak generation for visualization."""
import librosa
import numpy as np
from pathlib import Path
from typing import List, Optional
import json

from ..utils.logging import get_logger

logger = get_logger(__name__)


def generate_peaks(filepath: str, num_peaks: int = 800, use_cache: bool = True) -> List[float]:
    """Generate waveform peaks for visualization.

    Args:
        filepath: Path to audio file
        num_peaks: Number of peaks to generate (default: 800)
        use_cache: Whether to use cached peaks if available

    Returns:
        List of normalized peak values (0-1)
    """
    cache_file = Path(filepath).with_suffix('.peaks.json')

    # Try to load from cache
    if use_cache and cache_file.exists():
        try:
            with open(cache_file, 'r') as f:
                cached_data = json.load(f)
                if cached_data.get('num_peaks') == num_peaks:
                    logger.debug(f"Loading peaks from cache: {cache_file}")
                    return cached_data['peaks']
        except Exception as e:
            logger.warning(f"Failed to load cached peaks: {e}")

    try:
        logger.debug(f"Generating {num_peaks} peaks for {filepath}")

        # Load audio
        y, sr = librosa.load(filepath, sr=None, mono=True)

        # Calculate how many samples per peak
        total_samples = len(y)
        samples_per_peak = max(1, total_samples // num_peaks)

        peaks = []
        for i in range(num_peaks):
            start_idx = i * samples_per_peak
            end_idx = min(start_idx + samples_per_peak, total_samples)

            if start_idx >= total_samples:
                peaks.append(0.0)
                continue

            # Get chunk
            chunk = y[start_idx:end_idx]

            # Calculate peak (max absolute value)
            peak = float(np.max(np.abs(chunk))) if len(chunk) > 0 else 0.0
            peaks.append(peak)

        # Normalize peaks to 0-1 range
        max_peak = max(peaks) if peaks else 1.0
        if max_peak > 0:
            peaks = [p / max_peak for p in peaks]

        # Cache the peaks
        if use_cache:
            try:
                cache_data = {
                    'num_peaks': num_peaks,
                    'peaks': peaks,
                    'duration': float(librosa.get_duration(y=y, sr=sr))
                }
                with open(cache_file, 'w') as f:
                    json.dump(cache_data, f)
                logger.debug(f"Cached peaks to {cache_file}")
            except Exception as e:
                logger.warning(f"Failed to cache peaks: {e}")

        return peaks

    except Exception as e:
        logger.error(f"Failed to generate peaks for {filepath}: {e}")
        # Return empty peaks
        return [0.0] * num_peaks


def get_waveform_data(filepath: str, num_peaks: int = 800, waveform_cache_path: Optional[str] = None) -> dict:
    """Get complete waveform data including peaks and duration.

    Args:
        filepath: Path to audio file
        num_peaks: Number of peaks
        waveform_cache_path: Optional path to pre-computed waveform JSON file

    Returns:
        Dictionary with peaks and duration
    """
    # Try to load from provided cache path first
    if waveform_cache_path and Path(waveform_cache_path).exists():
        try:
            with open(waveform_cache_path, 'r') as f:
                cached_data = json.load(f)
                if cached_data.get('num_peaks') == num_peaks:
                    logger.debug(f"Loading peaks from provided cache: {waveform_cache_path}")
                    return cached_data
        except Exception as e:
            logger.warning(f"Failed to load from provided cache path: {e}")

    try:
        peaks = generate_peaks(filepath, num_peaks)

        # Get duration
        y, sr = librosa.load(filepath, sr=None, mono=True)
        duration = float(librosa.get_duration(y=y, sr=sr))

        return {
            'peaks': peaks,
            'duration': duration,
            'num_peaks': num_peaks
        }

    except Exception as e:
        logger.error(f"Failed to get waveform data: {e}")
        return {
            'peaks': [0.0] * num_peaks,
            'duration': 0.0,
            'num_peaks': num_peaks
        }


def save_waveform_to_file(filepath: str, output_path: str, num_peaks: int = 800) -> bool:
    """Generate and save waveform data to a JSON file.

    Args:
        filepath: Path to audio file
        output_path: Path to save waveform JSON
        num_peaks: Number of peaks to generate

    Returns:
        True if successful, False otherwise
    """
    try:
        waveform_data = get_waveform_data(filepath, num_peaks)

        # Save to file
        with open(output_path, 'w') as f:
            json.dump(waveform_data, f)

        logger.info(f"Saved waveform to {output_path}")
        return True

    except Exception as e:
        logger.error(f"Failed to save waveform: {e}")
        return False
