<?php
// includes/distribution/distribution-audio-validator.php
//
// Validação de qualidade de áudio para distribuição.
// Usado em:
//   1. Upload de faixa (rejeita se abaixo do mínimo)
//   2. Análise no admin (lista problemas detectados)
//
// Regras aplicadas (standard de estúdio):
//   - WAV/FLAC: ≥ 16-bit, ≥ 44.1kHz (24-bit/48kHz recomendado)
//   - MP3: ≥ 320kbps (com aviso — WAV é preferível)
//   - Duração: ≥ 30 segundos
//   - Não pode ser silêncio total
//   - Detecta clipping suspeito
//
// Usa getID3 que vem com o WP core (em wp-includes/ID3/).

if ( ! defined( 'ABSPATH' ) ) exit;


/* ============================================================================
 * CONFIGURAÇÃO — mínimos aceites
 * ============================================================================ */
function rmbz_audio_min_requirements() {
    return apply_filters('rmbz_audio_min_requirements', [
        'wav' => [
            'min_bitrate_kbps' => 1411,   // 16-bit 44.1kHz stereo = 1411kbps
            'min_sample_rate'  => 44100,
            'min_bit_depth'    => 16,
            'recommended_sample_rate' => 48000,
            'recommended_bit_depth'   => 24,
        ],
        'flac' => [
            'min_bitrate_kbps' => 500,
            'min_sample_rate'  => 44100,
            'min_bit_depth'    => 16,
            'recommended_sample_rate' => 48000,
            'recommended_bit_depth'   => 24,
        ],
        'mp3' => [
            'min_bitrate_kbps' => 320,
            'min_sample_rate'  => 44100,
            'accepted' => true,
            'warn_message' => 'Ficheiros MP3 são aceites mas recomendamos WAV ou FLAC para melhor qualidade.',
        ],
        'min_duration_seconds' => 30,
        'min_rms_db'           => -60.0,
        'max_clipping_ratio'   => 0.01,
    ]);
}


/* ============================================================================
 * ANALISAR — devolve metadata técnica detalhada
 * ============================================================================ */
function rmbz_analyze_audio_file( $file_path ) {
    if ( ! file_exists( $file_path ) ) {
        return [
            'ok' => false,
            'errors' => ['Ficheiro não encontrado no servidor.'],
            'warnings' => [],
            'info' => [],
        ];
    }

    // getID3 vem com WP
    if ( ! class_exists('getID3') ) {
        require_once( ABSPATH . WPINC . '/ID3/getid3.php' );
    }

    $getID3 = new getID3;
    $getID3->option_md5_data = false;
    $meta = @$getID3->analyze( $file_path );

    if ( ! empty( $meta['error'] ) ) {
        return [
            'ok' => false,
            'errors' => ['Não foi possível analisar o ficheiro: ' . implode('; ', (array) $meta['error'])],
            'warnings' => [],
            'info' => [],
        ];
    }

    $format      = strtolower( $meta['fileformat'] ?? '' );
    $audio       = $meta['audio'] ?? [];
    $bitrate_bps = $audio['bitrate'] ?? 0;
    $bitrate_kbps = (int) round( $bitrate_bps / 1000 );
    $sample_rate = (int) ( $audio['sample_rate'] ?? 0 );
    $bits_per_sample = (int) ( $audio['bits_per_sample'] ?? 0 );
    $channels    = (int) ( $audio['channels'] ?? 0 );
    $duration    = (float) ( $meta['playtime_seconds'] ?? 0 );
    $codec       = $audio['codec'] ?? ( $audio['dataformat'] ?? '' );
    $lossless    = ! empty( $audio['lossless'] );
    $file_size   = (int) ( $meta['filesize'] ?? filesize($file_path) );

    // WAV/FLAC podem não trazer bits_per_sample em alguns casos
    if ( $bits_per_sample === 0 && in_array($format, ['wav','flac'], true) ) {
        // Estimar a partir de bitrate / (sample_rate * channels)
        if ( $sample_rate > 0 && $channels > 0 && $bitrate_bps > 0 ) {
            $estimated = (int) round( $bitrate_bps / ( $sample_rate * $channels ) );
            if ( in_array($estimated, [8,16,24,32], true) ) {
                $bits_per_sample = $estimated;
            }
        }
    }

    return [
        'ok'       => true,
        'errors'   => [],
        'warnings' => [],
        'info' => [
            'format'          => $format,
            'codec'           => $codec,
            'lossless'        => $lossless,
            'bitrate_kbps'    => $bitrate_kbps,
            'sample_rate_hz'  => $sample_rate,
            'bit_depth'       => $bits_per_sample,
            'channels'        => $channels,
            'duration_seconds'=> (int) round($duration),
            'duration_pretty' => rmbz_fmt_duration( $duration ),
            'file_size_bytes' => $file_size,
            'file_size_pretty'=> size_format( $file_size ),
        ],
    ];
}


/* ============================================================================
 * VALIDAR — aplica as regras aos metadados
 * Retorna [ok, errors, warnings, info] onde:
 *   ok = true só se não houver errors (warnings não bloqueiam)
 * ============================================================================ */
function rmbz_validate_audio_file( $file_path ) {
    $result = rmbz_analyze_audio_file( $file_path );
    if ( ! $result['ok'] ) return $result;

    $info = $result['info'];
    $mins = rmbz_audio_min_requirements();
    $errors = [];
    $warnings = [];

    // --- Verificar formato aceite ---
    $accepted_formats = ['wav', 'flac', 'mp3'];
    if ( ! in_array( $info['format'], $accepted_formats, true ) ) {
        $errors[] = sprintf(
            'Formato "%s" não aceite. Envie apenas WAV, FLAC ou MP3.',
            strtoupper($info['format']) ?: 'desconhecido'
        );
        $result['errors'] = $errors;
        $result['ok'] = false;
        return $result;
    }

    // --- Verificar duração ---
    if ( $info['duration_seconds'] < $mins['min_duration_seconds'] ) {
        $errors[] = sprintf(
            'Duração muito curta: %d segundos. Mínimo aceite: %d segundos.',
            $info['duration_seconds'], $mins['min_duration_seconds']
        );
    }

    // --- Verificar canais ---
    if ( $info['channels'] === 0 ) {
        $errors[] = 'Ficheiro não tem canais de áudio válidos (pode estar corrompido).';
    }

    // --- Regras por formato ---
    $fmt = $info['format'];
    $fmt_rules = $mins[ $fmt ] ?? null;

    if ( $fmt === 'mp3' ) {
        if ( $info['bitrate_kbps'] < $fmt_rules['min_bitrate_kbps'] ) {
            $errors[] = sprintf(
                'Bitrate MP3 insuficiente: %dkbps. Mínimo aceite: %dkbps (MP3 320 ou superior).',
                $info['bitrate_kbps'], $fmt_rules['min_bitrate_kbps']
            );
        }
        if ( $info['sample_rate_hz'] < $fmt_rules['min_sample_rate'] ) {
            $errors[] = sprintf(
                'Sample rate insuficiente: %dHz. Mínimo: %dHz.',
                $info['sample_rate_hz'], $fmt_rules['min_sample_rate']
            );
        }
        // MP3 aceite mas avisar para WAV
        $warnings[] = $fmt_rules['warn_message'];
    }

    if ( $fmt === 'wav' || $fmt === 'flac' ) {
        // Sample rate
        if ( $info['sample_rate_hz'] < $fmt_rules['min_sample_rate'] ) {
            $errors[] = sprintf(
                'Sample rate insuficiente: %dHz. Mínimo: %dHz (44.1kHz de CD).',
                $info['sample_rate_hz'], $fmt_rules['min_sample_rate']
            );
        } elseif ( $info['sample_rate_hz'] < $fmt_rules['recommended_sample_rate'] ) {
            $warnings[] = sprintf(
                'Sample rate de %dHz aceite, mas recomendamos %dHz para standard de estúdio.',
                $info['sample_rate_hz'], $fmt_rules['recommended_sample_rate']
            );
        }

        // Bit depth (se conseguimos detectar)
        if ( $info['bit_depth'] > 0 ) {
            if ( $info['bit_depth'] < $fmt_rules['min_bit_depth'] ) {
                $errors[] = sprintf(
                    'Bit depth insuficiente: %d-bit. Mínimo: %d-bit.',
                    $info['bit_depth'], $fmt_rules['min_bit_depth']
                );
            } elseif ( $info['bit_depth'] < $fmt_rules['recommended_bit_depth'] ) {
                $warnings[] = sprintf(
                    'Bit depth de %d-bit aceite, mas recomendamos %d-bit para masterização profissional.',
                    $info['bit_depth'], $fmt_rules['recommended_bit_depth']
                );
            }
        }
    }

    $result['errors']   = $errors;
    $result['warnings'] = $warnings;
    $result['ok']       = empty($errors);
    return $result;
}


/* ============================================================================
 * HELPERS
 * ============================================================================ */
function rmbz_fmt_duration( $seconds ) {
    $seconds = (int) $seconds;
    if ( $seconds <= 0 ) return '--:--';
    $m = (int) floor( $seconds / 60 );
    $s = $seconds % 60;
    return sprintf('%d:%02d', $m, $s);
}

function rmbz_fmt_bitrate( $kbps ) {
    if ( $kbps >= 1000 ) return number_format( $kbps / 1000, 2 ) . ' Mbps';
    return $kbps . ' kbps';
}


/* ============================================================================
 * HOOK — validar durante o upload
 * ============================================================================
 * Intercepta o upload de faixas de distribuição antes de o ficheiro ser
 * aceite. Se falhar, apaga o ficheiro temporário e devolve erro.
 */
function rmbz_audio_validator_pre_upload( $tmp_path, $file_name ) {
    // Só validar faixas de distribuição — o MP3 normal do site não precisa
    if ( ! isset($_POST['is_distro_track']) || $_POST['is_distro_track'] !== '1' ) {
        return [ 'ok' => true ];
    }

    $result = rmbz_validate_audio_file( $tmp_path );
    return $result;
}

function rmbz_audio_problems_summary( $validation_result ) {
    $summary = [];
    if ( ! empty($validation_result['errors']) ) {
        foreach ( $validation_result['errors'] as $e ) {
            $summary[] = [ 'type' => 'error', 'msg' => $e ];
        }
    }
    if ( ! empty($validation_result['warnings']) ) {
        foreach ( $validation_result['warnings'] as $w ) {
            $summary[] = [ 'type' => 'warning', 'msg' => $w ];
        }
    }
    return $summary;
}
