import os
import numpy as np
import soundfile as sf
from pathlib import Path

TARGET_SR = 44100
TARGET_SUBTYPE = 'PCM_16'

SILENCE_THRESHOLD_DB = -50
MIN_SILENCE_DURATION = 0.01


def db_to_amplitude(db):
    return 10 ** (db / 20)


def find_sound_boundaries(audio, sr, threshold_db=SILENCE_THRESHOLD_DB):
    if len(audio.shape) > 1:
        audio_mono = np.mean(audio, axis=1)
    else:
        audio_mono = audio
    
    peak = np.max(np.abs(audio_mono))
    if peak == 0:
        return 0, len(audio_mono)
    
    threshold = peak * db_to_amplitude(threshold_db)
    
    above_threshold = np.abs(audio_mono) > threshold
    
    if not np.any(above_threshold):
        return 0, len(audio_mono)
    
    nonzero_indices = np.where(above_threshold)[0]
    start_idx = nonzero_indices[0]
    end_idx = nonzero_indices[-1] + 1
    
    start_buffer_samples = int(0.001 * sr)
    end_buffer_samples = int(0.005 * sr)
    start_idx = max(0, start_idx - start_buffer_samples)
    end_idx = min(len(audio_mono), end_idx + end_buffer_samples)
    
    return start_idx, end_idx


def trim_silence(input_path, output_path=None, threshold_db=SILENCE_THRESHOLD_DB):
    if output_path is None:
        output_path = input_path
    
    audio, sr = sf.read(input_path)
    original_duration = len(audio) / sr
    
    start_idx, end_idx = find_sound_boundaries(audio, sr, threshold_db)
    
    if len(audio.shape) > 1:
        trimmed_audio = audio[start_idx:end_idx, :]
    else:
        trimmed_audio = audio[start_idx:end_idx]
    
    trimmed_duration = len(trimmed_audio) / sr
    
    if sr != TARGET_SR:
        original_length = len(trimmed_audio)
        new_length = int(original_length * TARGET_SR / sr)
        
        if len(trimmed_audio.shape) > 1:
            resampled = np.zeros((new_length, trimmed_audio.shape[1]))
            for ch in range(trimmed_audio.shape[1]):
                resampled[:, ch] = np.interp(
                    np.linspace(0, original_length - 1, new_length),
                    np.arange(original_length),
                    trimmed_audio[:, ch]
                )
            trimmed_audio = resampled
        else:
            trimmed_audio = np.interp(
                np.linspace(0, original_length - 1, new_length),
                np.arange(original_length),
                trimmed_audio
            )
        
        trimmed_duration = len(trimmed_audio) / TARGET_SR
    
    sf.write(output_path, trimmed_audio, TARGET_SR, subtype=TARGET_SUBTYPE)
    
    return original_duration, trimmed_duration


def process_directory(directory='.', threshold_db=SILENCE_THRESHOLD_DB, backup=False):
    directory = Path(directory)
    wav_files = list(directory.glob('*.wav')) + list(directory.glob('*.WAV'))
    
    if not wav_files:
        print(f"No .wav files found in {directory.absolute()}")
        return
    
    print(f"Found {len(wav_files)} .wav file(s) to process")
    print(f"Silence threshold: {threshold_db} dB")
    print(f"Target sample rate: {TARGET_SR} Hz")
    print(f"Target format: {TARGET_SUBTYPE}")
    print("-" * 60)
    
    total_saved = 0
    
    for wav_file in wav_files:
        try:
            if backup:
                backup_path = wav_file.with_suffix('.wav.bak')
                if not backup_path.exists():
                    import shutil
                    shutil.copy2(wav_file, backup_path)
            
            original_dur, trimmed_dur = trim_silence(
                str(wav_file), 
                threshold_db=threshold_db
            )
            
            saved = original_dur - trimmed_dur
            total_saved += saved
            
            print(f"✓ {wav_file.name}")
            print(f"  Original: {original_dur:.2f}s → Trimmed: {trimmed_dur:.2f}s "
                  f"(removed {saved:.2f}s)")
            
        except Exception as e:
            print(f"✗ {wav_file.name}: Error - {e}")
    
    print("-" * 60)
    print(f"Total silence removed: {total_saved:.2f}s")


if __name__ == '__main__':
    import argparse
    
    parser = argparse.ArgumentParser(
        description='Trim silence from .wav files in a directory'
    )
    parser.add_argument(
        '-d', '--directory',
        default='.',
        help='Directory containing .wav files (default: current directory)'
    )
    parser.add_argument(
        '-t', '--threshold',
        type=float,
        default=SILENCE_THRESHOLD_DB,
        help=f'Silence threshold in dB below peak (default: {SILENCE_THRESHOLD_DB})'
    )
    parser.add_argument(
        '-b', '--backup',
        action='store_true',
        help='Create backup files before overwriting'
    )
    
    args = parser.parse_args()
    
    process_directory(
        directory=args.directory,
        threshold_db=args.threshold,
        backup=args.backup
    )