"""优化版音频播放器，专门针对网络文件播放进行优化"""

from __future__ import annotations

import logging
import os
import threading
import time
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Callable

import numpy as np
import sounddevice as sd
import soundfile as sf

logger = logging.getLogger(__name__)


class PlaybackState(Enum):
    """Enumeration of possible playback states."""

    STOPPED = "stopped"
    PLAYING = "playing"
    PAUSED = "paused"


@dataclass
class AudioTrack:
    """Data class representing an audio track."""

    file_path: Path
    title: str
    artist: str
    album: str
    duration: float
    file_size: int


class NetworkAudioOptimizer:
    """网络音频播放优化器 - 增强版支持跳转功能"""

    def __init__(self, buffer_size_mb: int = 10, timeout_seconds: int = 30):
        self.buffer_size_bytes = buffer_size_mb * 1024 * 1024
        self.timeout_seconds = timeout_seconds
        self.is_network_file = False
        self.preload_thread = None
        self.preload_complete = threading.Event()
        self.cached_data = None
        self.cached_sample_rate = None
        self.loading_progress = 0.0
        self.error_message = None

        # 网络跳转增强功能
        self._lock = threading.RLock()  # 添加线程锁
        self.chunk_cache = {}  # 分段缓存: {start_frame: audio_data}
        self.chunk_size_frames = 44100 * 5  # 5秒为一个片段
        self.current_chunk = 0  # 当前播放的片段索引
        self.seek_pending = False  # 是否有待处理的跳转请求
        self.target_seek_position = 0.0  # 目标跳转位置

    def detect_network_path(self, file_path: Path) -> bool:
        """检测是否为网络路径"""
        path_str = str(file_path).lower()
        network_indicators = [
            "\\\\",  # Windows网络路径
            "smb://",  # SMB协议
            "nfs://",  # NFS协议
            "http://",  # HTTP
            "https://",  # HTTPS
        ]
        return any(indicator in path_str for indicator in network_indicators)

    def seek_network_position(
        self, file_path: Path, target_position: float, sample_rate: int
    ) -> tuple[np.ndarray | None, bool]:
        """网络文件位置跳转

        Args:
            file_path: 文件路径
            target_position: 目标位置（秒）
            sample_rate: 采样率

        Returns:
            Tuple[音频数据, 是否需要等待加载]
        """
        if not self.is_network_file:
            return None, False

        target_frame = int(target_position * sample_rate)
        chunk_index = target_frame // self.chunk_size_frames
        chunk_start_frame = chunk_index * self.chunk_size_frames

        logger.info(
            f"网络跳转到位置: {target_position:.2f}s (帧 {target_frame}, 片段 {chunk_index})"
        )

        # 检查是否已在缓存中
        if chunk_start_frame in self.chunk_cache:
            logger.info(f"片段 {chunk_index} 已在缓存中")
            # 返回缓存数据的相对位置
            chunk_data = self.chunk_cache[chunk_start_frame]
            relative_frame = target_frame - chunk_start_frame
            if relative_frame < len(chunk_data):
                # 截取从目标位置开始的数据
                remaining_data = chunk_data[relative_frame:]
                return remaining_data, False

        # 需要加载新片段
        logger.info(f"需要加载片段 {chunk_index}")
        self.seek_pending = True
        self.target_seek_position = target_position

        # 启动后台加载
        def load_chunk_background():
            try:
                chunk_data = self._load_audio_chunk(
                    file_path, chunk_start_frame, self.chunk_size_frames
                )
                if chunk_data is not None:
                    with self._lock:
                        self.chunk_cache[chunk_start_frame] = chunk_data
                        logger.info(
                            f"片段 {chunk_index} 加载完成，长度: {len(chunk_data)} 帧"
                        )
                        self.seek_pending = False
            except Exception as e:
                logger.error(f"片段加载失败: {e}")
                self.seek_pending = False

        load_thread = threading.Thread(target=load_chunk_background, daemon=True)
        load_thread.start()

        return None, True  # 需要等待加载

    def _load_audio_chunk(
        self, file_path: Path, start_frame: int, num_frames: int
    ) -> np.ndarray | None:
        """加载音频文件的指定片段"""
        try:
            with sf.SoundFile(str(file_path)) as f:
                # 移动到起始位置
                f.seek(start_frame)
                # 读取指定帧数
                chunk_data = f.read(frames=num_frames, dtype="float32")

                if chunk_data is not None and len(chunk_data) > 0:
                    # 转换为立体声
                    if chunk_data.ndim == 1:
                        chunk_data = np.column_stack([chunk_data, chunk_data])
                    return chunk_data
        except Exception as e:
            logger.error(f"加载音频片段失败: {e}")

        return None

    def preload_adjacent_chunks(
        self, file_path: Path, current_position: float, sample_rate: int
    ) -> None:
        """预加载相邻片段以提高跳转响应速度"""
        if not self.is_network_file:
            return

        current_frame = int(current_position * sample_rate)
        current_chunk = current_frame // self.chunk_size_frames

        # 预加载前后各一个片段
        for offset in [-1, 1]:
            adjacent_chunk = current_chunk + offset
            if adjacent_chunk < 0:
                continue

            start_frame = adjacent_chunk * self.chunk_size_frames
            if start_frame not in self.chunk_cache:
                # 后台预加载
                def preload_background(chunk_idx, start_frm):
                    try:
                        chunk_data = self._load_audio_chunk(
                            file_path, start_frm, self.chunk_size_frames
                        )
                        if chunk_data is not None:
                            with self._lock:
                                self.chunk_cache[start_frm] = chunk_data
                                logger.debug(f"预加载片段 {chunk_idx} 完成")
                    except Exception as e:
                        logger.debug(f"预加载片段 {chunk_idx} 失败: {e}")

                preload_thread = threading.Thread(
                    target=lambda: preload_background(adjacent_chunk, start_frame),
                    daemon=True,
                )
                preload_thread.start()

    def load_audio_with_timeout(
        self, file_path: Path
    ) -> tuple[np.ndarray | None, int | None]:
        """带超时控制的音频加载"""
        result_data = None
        result_sr = None
        error_occurred = threading.Event()

        def load_target():
            nonlocal result_data, result_sr
            try:
                logger.info(f"开始加载音频文件: {file_path}")

                # 检测是否为网络文件
                self.is_network_file = self.detect_network_path(file_path)

                if self.is_network_file:
                    logger.info("检测到网络文件，启用优化加载")
                    result_data, result_sr = self._load_network_audio(file_path)
                else:
                    # 本地文件使用标准加载
                    result_data, result_sr = sf.read(str(file_path), dtype="float32")

                    # 转换为立体声
                    if result_data.ndim == 1:
                        result_data = np.column_stack([result_data, result_data])

                logger.info(f"音频加载完成: {result_sr}Hz, {len(result_data)}帧")

            except Exception as e:
                logger.error(f"音频加载失败: {e}")
                self.error_message = str(e)
                error_occurred.set()

        # 在单独线程中执行加载
        load_thread = threading.Thread(target=load_target, daemon=True)
        load_thread.start()

        # 等待加载完成或超时
        load_thread.join(timeout=self.timeout_seconds)

        if load_thread.is_alive():
            logger.warning(f"音频加载超时 ({self.timeout_seconds}秒)")
            self.error_message = "加载超时，请检查网络连接"
            return None, None

        if error_occurred.is_set():
            return None, None

        return result_data, result_sr

    def _load_network_audio(self, file_path: Path) -> tuple[np.ndarray, int]:
        """优化的网络音频加载"""
        try:
            # 先获取文件信息而不完全加载
            with sf.SoundFile(str(file_path)) as f:
                total_frames = f.frames
                sample_rate = f.samplerate
                channels = f.channels

                logger.info(
                    f"文件信息: {total_frames}帧, {sample_rate}Hz, {channels}声道"
                )

                # 计算合理的缓冲区大小
                bytes_per_frame = channels * 4  # float32
                max_frames = min(
                    total_frames, self.buffer_size_bytes // bytes_per_frame
                )

                logger.info(
                    f"将加载前 {max_frames}/{total_frames} 帧 ({max_frames / total_frames * 100:.1f}%)"
                )

                # 分块加载以提供进度反馈
                chunk_size = min(44100, max_frames)  # 每次最多读取1秒的数据
                loaded_frames = 0
                audio_chunks = []

                while loaded_frames < max_frames:
                    frames_to_read = min(chunk_size, max_frames - loaded_frames)
                    chunk = f.read(frames=frames_to_read, dtype="float32")

                    if len(chunk) == 0:
                        break

                    audio_chunks.append(chunk)
                    loaded_frames += len(chunk)
                    self.loading_progress = loaded_frames / max_frames

                    logger.debug(f"加载进度: {self.loading_progress * 100:.1f}%")

                # 合并所有块
                if audio_chunks:
                    audio_data = np.concatenate(audio_chunks, axis=0)
                else:
                    raise Exception("未能读取任何音频数据")

                # 转换为立体声
                if audio_data.ndim == 1:
                    audio_data = np.column_stack([audio_data, audio_data])

                return audio_data, sample_rate

        except Exception as e:
            logger.error(f"网络音频加载失败: {e}")
            raise


class StreamBufferManager:
    """流式缓冲管理器，实现高效的音频数据流处理"""

    def __init__(self, buffer_size: int = 1024 * 1024):  # 1MB缓冲区
        self.buffer_size = buffer_size
        self.buffers = {}  # 文件路径 -> 缓冲区映射
        self.access_times = {}  # 访问时间记录
        self.max_buffers = 10  # 最大缓冲区数量

    def get_buffer(self, file_path: Path) -> np.ndarray | None:
        """获取文件的缓冲数据"""
        key = str(file_path)
        if key in self.buffers:
            self.access_times[key] = time.time()
            return self.buffers[key]
        return None

    def set_buffer(self, file_path: Path, data: np.ndarray) -> None:
        """设置文件缓冲数据"""
        key = str(file_path)
        # 如果缓冲区满，移除最久未访问的
        if len(self.buffers) >= self.max_buffers:
            self._evict_lru()

        self.buffers[key] = data
        self.access_times[key] = time.time()

    def _evict_lru(self) -> None:
        """移除最少使用的缓冲区"""
        if not self.access_times:
            return
        lru_key = min(self.access_times.keys(), key=self.access_times.get)
        del self.buffers[lru_key]
        del self.access_times[lru_key]

    def clear_old_buffers(self, max_age: float = 300) -> None:
        """清理超过指定时间的缓冲区"""
        current_time = time.time()
        keys_to_remove = [
            key
            for key, access_time in self.access_times.items()
            if current_time - access_time > max_age
        ]
        for key in keys_to_remove:
            del self.buffers[key]
            del self.access_times[key]


class OptimizedAudioPlayer:
    """优化版音频播放器"""

    def __init__(self) -> None:
        """Initialize optimized audio player with streaming support."""
        self._state: PlaybackState = PlaybackState.STOPPED
        self._stream_buffer = StreamBufferManager()  # 添加流式缓冲管理
        self._current_track: AudioTrack | None = None
        self._volume: float = 0.7
        self._position: float = 0.0
        self._lock = threading.RLock()
        self._progress_callback: Callable[[float], None] | None = None
        self._play_thread: threading.Thread | None = None
        self._should_stop = threading.Event()
        self._audio_stream = None
        self._audio_data = None
        self._sample_rate = None
        self._current_frame = 0
        self._optimizer = NetworkAudioOptimizer()

        # 状态监控
        self._loading_status = "就绪"
        self._last_error = None

    @property
    def state(self) -> PlaybackState:
        """Get current playback state."""
        with self._lock:
            return self._state

    @property
    def current_track(self) -> AudioTrack | None:
        """Get currently loaded track."""
        with self._lock:
            return self._current_track

    @property
    def volume(self) -> float:
        """Get current volume level (0.0 to 1.0)."""
        with self._lock:
            return self._volume

    @volume.setter
    def volume(self, value: float) -> None:
        """Set volume level with validation."""
        with self._lock:
            self._volume = max(0.0, min(1.0, value))

    @property
    def position(self) -> float:
        """Get current playback position in seconds."""
        with self._lock:
            return self._position

    @property
    def loading_status(self) -> str:
        """获取加载状态"""
        return self._loading_status

    @property
    def last_error(self) -> str | None:
        """获取最后的错误信息"""
        return self._last_error

    def _update_loading_status(self, status: str) -> None:
        """更新加载状态"""
        self._loading_status = status
        logger.info(f"加载状态: {status}")

    def _load_audio_file(self, file_path: Path) -> bool:
        """优化的音频文件加载，包含增强错误处理"""
        try:
            self._update_loading_status("正在检测文件...")

            # 诊断文件问题
            diagnosis = self.diagnose_file_issues(file_path)
            logger.info(f"文件诊断结果: {diagnosis}")

            if not diagnosis["file_exists"]:
                self._last_error = "文件不存在"
                self._update_loading_status("文件不存在")
                return False

            if not diagnosis["file_readable"]:
                self._last_error = "文件不可读，请检查权限"
                self._update_loading_status("文件权限错误")
                return False

            # 使用增强错误处理加载音频
            self._update_loading_status("开始加载音频...")
            audio_data, sample_rate = self._load_with_enhanced_error_handling(file_path)

            if audio_data is None or sample_rate is None:
                self._last_error = self._optimizer.error_message or "未知错误"
                self._update_loading_status(f"加载失败: {self._last_error}")
                return False

            self._audio_data = audio_data
            self._sample_rate = sample_rate

            self._update_loading_status("加载完成")
            logger.info(f"音频文件加载成功: {file_path.name} ({sample_rate}Hz)")
            return True

        except Exception as e:
            self._last_error = str(e)
            self._update_loading_status(f"加载异常: {e}")
            logger.error(f"音频文件加载异常: {e}")
            return False

    def set_progress_callback(self, callback: Callable[[float], None]) -> None:
        """Set callback function for progress updates."""
        with self._lock:
            self._progress_callback = callback

    def load_track(self, track: AudioTrack) -> bool:
        """Load an audio track for playback with optimization."""
        with self._lock:
            try:
                self._update_loading_status("正在检查文件...")

                if not track.file_path.exists():
                    self._last_error = f"文件不存在: {track.file_path}"
                    logger.error(self._last_error)
                    return False

                # Stop current playback
                self._stop_internal()
                self._update_loading_status("停止当前播放")

                # Load new track with optimization
                self._update_loading_status("开始加载音频...")
                if not self._load_audio_file(track.file_path):
                    return False

                self._current_track = track
                self._state = PlaybackState.STOPPED
                self._position = 0.0
                self._current_frame = 0

                self._update_loading_status("轨道加载完成")
                logger.info(f"轨道加载成功: {track.title} by {track.artist}")
                return True

            except Exception as e:
                self._last_error = str(e)
                self._update_loading_status(f"加载错误: {e}")
                logger.error(f"轨道加载失败: {e}")
                return False

    def play(self) -> bool:
        """Start playback of currently loaded track."""
        with self._lock:
            if self._current_track is None:
                self._last_error = "没有加载轨道"
                logger.warning(self._last_error)
                return False

            try:
                self._should_stop.clear()
                self._play_thread = threading.Thread(
                    target=self._play_audio_stream, daemon=True
                )
                self._play_thread.start()
                self._state = PlaybackState.PLAYING
                self._update_loading_status("正在播放")
                logger.info(f"开始播放: {self._current_track.title}")
                return True

            except Exception as e:
                self._last_error = str(e)
                logger.error(f"播放启动失败: {e}")
                return False

    def pause(self) -> None:
        """Pause current playback."""
        with self._lock:
            if self._state == PlaybackState.PLAYING:
                self._should_stop.set()
                if self._play_thread:
                    self._play_thread.join(timeout=1.0)
                self._state = PlaybackState.PAUSED
                self._update_loading_status("已暂停")
                logger.info("播放已暂停")

    def resume(self) -> bool:
        """Resume paused playback."""
        with self._lock:
            if self._state == PlaybackState.PAUSED:
                try:
                    return self.play()
                except Exception as e:
                    self._last_error = str(e)
                    logger.error(f"恢复播放失败: {e}")
                    return False
            return False

    def stop(self) -> None:
        """Stop playback and reset position."""
        with self._lock:
            self._stop_internal()
            self._update_loading_status("已停止")
            logger.info("播放已停止")

    def seek(self, position: float) -> bool:
        """Seek to specific position in current track.

        Args:
            position: Position in seconds

        Returns:
            True if seek successful, False otherwise
        """
        logger.info(f"seek() called with position={position:.2f}s")

        # 在获取锁之前检查播放状态，避免死锁
        was_playing = self._state == PlaybackState.PLAYING
        logger.info(f"Current state: {self._state.value}, was_playing={was_playing}")

        with self._lock:
            logger.debug("Lock acquired")

            if self._current_track is None or self._sample_rate is None:
                logger.warning(
                    "Cannot seek: No track loaded or sample rate unavailable"
                )
                return False

            logger.info(f"Current track: {self._current_track.title}, sample_rate={self._sample_rate}Hz")

            try:
                # 对于网络文件，使用特殊的跳转处理
                if (
                    self._optimizer.is_network_file
                    and self._optimizer.seek_network_position
                ):
                    logger.info(f"处理网络文件跳转: {position:.2f}s")

                    # 调用网络跳转方法
                    audio_chunk, needs_wait = self._optimizer.seek_network_position(
                        self._current_track.file_path, position, self._sample_rate
                    )

                    if audio_chunk is not None:
                        # 使用新加载的音频数据
                        self._audio_data = audio_chunk
                        self._current_frame = 0
                        self._position = position
                        logger.info(f"网络跳转成功: {position:.2f}s")

                        # 如果之前在播放，自动恢复播放
                        if was_playing:
                            logger.info("停止旧播放线程并启动新线程")
                            self._should_stop.set()
                            if self._play_thread:
                                self._play_thread.join(timeout=1.0)
                                logger.info("旧播放线程已停止")

                            # 启动新播放线程
                            self._should_stop.clear()
                            self._play_thread = threading.Thread(
                                target=self._play_audio_stream, daemon=True
                            )
                            self._play_thread.start()
                            self._state = PlaybackState.PLAYING
                            logger.info("新播放线程已启动")
                        return True
                    elif needs_wait:
                        # 需要等待后台加载完成
                        logger.info(f"网络跳转需要等待加载: {position:.2f}s")
                        # 这里可以设置等待状态或返回特殊标识
                        return False
                    else:
                        logger.warning(f"网络跳转失败: {position:.2f}s")
                        return False

                # 本地文件使用原有逻辑
                if self._audio_data is None:
                    logger.warning("Cannot seek: Audio data unavailable")
                    return False

                logger.info(f"Audio data available: {len(self._audio_data)} frames")

                # Calculate frame position
                target_frame = int(position * self._sample_rate)
                total_frames = len(self._audio_data)

                logger.info(f"Target frame: {target_frame}, Total frames: {total_frames}")

                # Validate bounds
                if 0 <= target_frame < total_frames:
                    # Update internal state
                    self._current_frame = target_frame
                    self._position = position

                    logger.info(
                        f"Seeked to position: {position:.2f}s (frame {target_frame})"
                    )

                    # 如果之前在播放，自动恢复播放
                    if was_playing:
                        logger.info("停止旧播放线程并启动新线程")
                        self._should_stop.set()
                        if self._play_thread:
                            self._play_thread.join(timeout=1.0)
                            logger.info("旧播放线程已停止")

                        # 启动新播放线程
                        self._should_stop.clear()
                        self._play_thread = threading.Thread(
                            target=self._play_audio_stream, daemon=True
                        )
                        self._play_thread.start()
                        self._state = PlaybackState.PLAYING
                        logger.info("新播放线程已启动")
                    return True
                else:
                    logger.warning(
                        f"Seek position out of bounds: {position}s (frame {target_frame}, total {total_frames})"
                    )
                    return False

            except Exception as e:
                logger.error(f"Failed to seek to position {position}: {e}")
                import traceback
                traceback.print_exc()
                return False

    def _play_audio_stream(self) -> None:
        """Internal method to play audio using sounddevice stream."""
        if self._audio_data is None or self._sample_rate is None:
            self._last_error = "没有音频数据"
            logger.error(self._last_error)
            return

        try:
            # Audio callback function
            def audio_callback(outdata, frames, time, status):
                if status:
                    logger.warning(f"音频回调状态: {status}")

                if self._should_stop.is_set():
                    outdata.fill(0)
                    raise sd.CallbackStop()

                # Calculate end frame
                end_frame = self._current_frame + frames
                if end_frame > len(self._audio_data):
                    # End of audio
                    remaining = len(self._audio_data) - self._current_frame
                    if remaining > 0:
                        outdata[:remaining] = (
                            self._audio_data[self._current_frame : end_frame]
                            * self._volume
                        )
                        outdata[remaining:].fill(0)
                    else:
                        outdata.fill(0)
                    raise sd.CallbackStop()
                else:
                    # Normal playback
                    outdata[:] = (
                        self._audio_data[self._current_frame : end_frame] * self._volume
                    )
                    self._current_frame = end_frame

                    # Update position
                    with self._lock:
                        self._position = self._current_frame / self._sample_rate

                        # 智能预加载：定期预加载相邻片段
                        if (
                            self._current_frame % (self._sample_rate * 10)
                            == 0  # 每10秒检查一次
                            and self._optimizer.is_network_file
                            and hasattr(self._optimizer, "preload_adjacent_chunks")
                        ):
                            try:
                                self._optimizer.preload_adjacent_chunks(
                                    self._current_track.file_path,
                                    self._position,
                                    self._sample_rate,
                                )
                            except Exception as e:
                                logger.debug(f"预加载失败: {e}")

                        # Call progress callback if set
                        if self._progress_callback:
                            self._progress_callback(self._position)

            # Create and start audio stream
            with sd.OutputStream(
                samplerate=self._sample_rate,
                channels=self._audio_data.shape[1],
                callback=audio_callback,
                blocksize=1024,
            ) as stream:
                self._audio_stream = stream
                stream.start()

                # Non-blocking wait for playback completion
                while stream.active and not self._should_stop.is_set():
                    time.sleep(0.1)

        except Exception as e:
            self._last_error = str(e)
            logger.error(f"音频播放错误: {e}")
        finally:
            with self._lock:
                if not self._should_stop.is_set():
                    self._state = PlaybackState.STOPPED
                    self._position = 0.0
                    self._current_frame = 0

    def _stop_internal(self) -> None:
        """Internal method to stop playback without logging."""
        self._should_stop.set()
        if self._play_thread:
            self._play_thread.join(timeout=1.0)
        self._state = PlaybackState.STOPPED
        self._position = 0.0

    def cleanup(self) -> None:
        """Clean up audio resources."""
        with self._lock:
            self._stop_internal()
            self._audio_data = None
            self._sample_rate = None
            self._current_track = None
            self._update_loading_status("资源已清理")

    def get_supported_formats(self) -> list[str]:
        """Get list of supported audio formats."""
        return ["wav", "mp3", "flac", "ogg", "aiff"]

    def is_supported_format(self, file_path: Path) -> bool:
        """Check if file format is supported."""
        return file_path.suffix.lower()[1:] in self.get_supported_formats()

    def _load_with_enhanced_error_handling(
        self, file_path: Path
    ) -> tuple[np.ndarray, int]:
        """增强错误处理的音频加载方法"""
        errors = []

        # 方法1: 标准soundfile加载
        try:
            logger.info(f"方法1 - 标准加载: {file_path}")
            audio_data, sample_rate = sf.read(str(file_path), dtype="float32")
            if audio_data is not None and len(audio_data) > 0:
                # 转换为立体声
                if audio_data.ndim == 1:
                    audio_data = np.column_stack([audio_data, audio_data])
                logger.info(f"标准加载成功: {len(audio_data)}帧, {sample_rate}Hz")
                return audio_data, sample_rate
        except Exception as e:
            error_msg = f"标准加载失败: {e!s}"
            logger.warning(error_msg)
            errors.append(error_msg)

        # 方法2: 分块加载
        try:
            logger.info(f"方法2 - 分块加载: {file_path}")
            with sf.SoundFile(str(file_path)) as f:
                total_frames = f.frames
                sample_rate = f.samplerate

                # 小块加载测试
                chunk_size = min(10000, total_frames)  # 先加载小块测试
                audio_data = f.read(frames=chunk_size, dtype="float32")

                if audio_data is not None and len(audio_data) > 0:
                    # 转换为立体声
                    if audio_data.ndim == 1:
                        audio_data = np.column_stack([audio_data, audio_data])
                    logger.info(f"分块加载成功: {len(audio_data)}帧, {sample_rate}Hz")
                    return audio_data, sample_rate
        except Exception as e:
            error_msg = f"分块加载失败: {e!s}"
            logger.warning(error_msg)
            errors.append(error_msg)

        # 方法3: 文件信息检查
        try:
            logger.info(f"方法3 - 文件信息检查: {file_path}")
            info = sf.info(str(file_path))
            logger.info(
                f"文件信息 - 采样率:{info.samplerate}, 声道:{info.channels}, 帧数:{info.frames}"
            )
            logger.info(f"格式:{info.format}, 子类型:{info.subtype}")
        except Exception as e:
            error_msg = f"文件信息检查失败: {e!s}"
            logger.error(error_msg)
            errors.append(error_msg)

        # 所有方法都失败
        error_summary = "; ".join(errors)
        raise Exception(f"所有音频加载方法都失败: {error_summary}")

    def _load_with_enhanced_error_handling(
        self, file_path: Path
    ) -> tuple[np.ndarray | None, int | None]:
        """使用增强错误处理加载音频文件"""
        errors = []

        # 方法1: 标准soundfile加载
        try:
            logger.info(f"方法1 - 标准加载: {file_path}")
            audio_data, sample_rate = sf.read(str(file_path), dtype="float32")

            # 转换为立体声
            if audio_data.ndim == 1:
                audio_data = np.column_stack([audio_data, audio_data])

            logger.info(f"标准加载成功: {len(audio_data)}帧, {sample_rate}Hz")
            return audio_data, sample_rate
        except Exception as e:
            error_msg = f"标准加载失败: {e!s}"
            logger.warning(error_msg)
            errors.append(error_msg)

        # 方法2: 分块加载
        try:
            logger.info(f"方法2 - 分块加载: {file_path}")
            with sf.SoundFile(str(file_path)) as f:
                total_frames = f.frames
                sample_rate = f.samplerate

                # 小块加载测试
                chunk_size = min(10000, total_frames)  # 先加载小块测试
                audio_data = f.read(frames=chunk_size, dtype="float32")

                if audio_data is not None and len(audio_data) > 0:
                    # 转换为立体声
                    if audio_data.ndim == 1:
                        audio_data = np.column_stack([audio_data, audio_data])
                    logger.info(f"分块加载成功: {len(audio_data)}帧, {sample_rate}Hz")
                    return audio_data, sample_rate
        except Exception as e:
            error_msg = f"分块加载失败: {e!s}"
            logger.warning(error_msg)
            errors.append(error_msg)

        # 方法3: 文件信息检查
        try:
            logger.info(f"方法3 - 文件信息检查: {file_path}")
            info = sf.info(str(file_path))
            logger.info(
                f"文件信息 - 采样率:{info.samplerate}, 声道:{info.channels}, 帧数:{info.frames}"
            )
            logger.info(f"格式:{info.format}, 子类型:{info.subtype}")
        except Exception as e:
            error_msg = f"文件信息检查失败: {e!s}"
            logger.error(error_msg)
            errors.append(error_msg)

        # 所有方法都失败
        error_summary = "; ".join(errors)
        raise Exception(f"所有音频加载方法都失败: {error_summary}")

    def diagnose_file_issues(self, file_path: Path) -> dict:
        """诊断文件问题"""
        diagnosis = {
            "file_exists": False,
            "file_readable": False,
            "file_size": 0,
            "soundfile_info": None,
            "errors": [],
        }

        try:
            # 检查文件存在性
            diagnosis["file_exists"] = file_path.exists()
            if not diagnosis["file_exists"]:
                diagnosis["errors"].append("文件不存在")
                return diagnosis

            # 检查文件可读性
            diagnosis["file_size"] = file_path.stat().st_size
            diagnosis["file_readable"] = os.access(file_path, os.R_OK)
            if not diagnosis["file_readable"]:
                diagnosis["errors"].append("文件不可读")
                return diagnosis

            # 获取soundfile信息
            try:
                info = sf.info(str(file_path))
                diagnosis["soundfile_info"] = {
                    "samplerate": info.samplerate,
                    "channels": info.channels,
                    "frames": info.frames,
                    "duration": info.duration,
                    "format": info.format,
                    "subtype": info.subtype,
                }
            except Exception as e:
                diagnosis["errors"].append(f"soundfile无法读取文件信息: {e!s}")

        except Exception as e:
            diagnosis["errors"].append(f"诊断过程中出现错误: {e!s}")

        return diagnosis
