using System;
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

public class DownloadManager : MonoBehaviour
{
    [SerializeField] private string baseUrl = "http://whdwo798.synology.me/beatsaber";

    private static string CacheRoot => Path.Combine(Application.temporaryCachePath, "beatsaber");

    // ── Public API ───────────────────────────────────────────

    public void FetchSongsList(Action<SongsList> onSuccess, Action<string> onError = null)
    {
        StartCoroutine(GetText($"{baseUrl}/songs.json", json =>
        {
            SongsList list = JsonUtility.FromJson<SongsList>(json);
            if (list == null)
                onError?.Invoke("songs.json 파싱 실패");
            else
                onSuccess?.Invoke(list);
        }, onError));
    }

    // 오디오 + 선택 난이도 맵 다운로드
    public void DownloadSong(SongInfo song, string difficulty,
        Action<float> onProgress, Action onComplete, Action<string> onError = null)
    {
        StartCoroutine(DownloadSongCoroutine(song, difficulty, onProgress, onComplete, onError));
    }

    public void DeleteSong(string songId)
    {
        string dir = SongDir(songId);
        if (Directory.Exists(dir))
        {
            Directory.Delete(dir, recursive: true);
            Debug.Log($"[DownloadManager] 삭제: {songId}");
        }
    }

    public void DeleteDifficulty(SongInfo song, string difficulty)
    {
        string path = MapPath(song, difficulty);
        if (path != null && File.Exists(path))
            File.Delete(path);
    }

    public bool IsSongDownloaded(string songId)
        => File.Exists(AudioPath(songId));

    public bool IsDifficultyDownloaded(SongInfo song, string difficulty)
    {
        string path = MapPath(song, difficulty);
        return path != null && File.Exists(path);
    }

    // Spawner에서 재생 경로를 얻을 때 사용
    public string AudioPath(string songId)
        => Path.Combine(SongDir(songId), $"{songId}.mp3");

    public string MapPath(SongInfo song, string difficulty)
    {
        DifficultyInfo info = song.difficulties.Get(difficulty);
        if (info == null || string.IsNullOrEmpty(info.mapFile)) return null;
        string fileName = Path.GetFileName(info.mapFile);
        if (string.IsNullOrEmpty(fileName)) return null;
        return Path.Combine(SongDir(song.id), fileName);
    }

    // ── 내부 구현 ─────────────────────────────────────────────

    private IEnumerator DownloadSongCoroutine(SongInfo song, string difficulty,
        Action<float> onProgress, Action onComplete, Action<string> onError)
    {
        string songDir = Path.GetFullPath(SongDir(song.id));
        Directory.CreateDirectory(songDir);

        // 1단계: 오디오 (70%)
        string audioPath = Path.Combine(songDir, $"{song.id}.mp3");
        if (!File.Exists(audioPath))
        {
            bool failed = false;
            yield return DownloadFile(
                $"{baseUrl}/{song.audioFile}", audioPath,
                p => onProgress?.Invoke(p * 0.7f),
                err => { onError?.Invoke(err); failed = true; });
            if (failed) yield break;
        }

        // 2단계: 맵 파일 (30%)
        DifficultyInfo diffInfo = song.difficulties.Get(difficulty);
        if (diffInfo == null)
        {
            onError?.Invoke($"난이도 '{difficulty}' 없음");
            yield break;
        }

        if (string.IsNullOrEmpty(diffInfo.mapFile))
        {
            onError?.Invoke($"'{difficulty}' 맵 파일 정보 없음 — Creator에서 곡을 다시 생성해주세요");
            yield break;
        }

        string mapPath = MapPath(song, difficulty);
        if (mapPath != null) mapPath = Path.GetFullPath(mapPath);
        if (mapPath == null)
        {
            onError?.Invoke($"'{difficulty}' 맵 경로 계산 실패");
            yield break;
        }
        if (!File.Exists(mapPath))
        {
            bool failed = false;
            yield return DownloadFile(
                $"{baseUrl}/{diffInfo.mapFile}", mapPath,
                p => onProgress?.Invoke(0.7f + p * 0.3f),
                err => { onError?.Invoke(err); failed = true; });
            if (failed) yield break;
        }

        onProgress?.Invoke(1f);
        onComplete?.Invoke();
        Debug.Log($"[DownloadManager] 완료: {song.title} ({difficulty})");
    }

    private IEnumerator DownloadFile(string url, string savePath,
        Action<float> onProgress, Action<string> onError)
    {
        using var req = UnityWebRequest.Get(url);
        req.downloadHandler = new DownloadHandlerFile(savePath);
        req.SendWebRequest();

        while (!req.isDone)
        {
            onProgress?.Invoke(req.downloadProgress);
            yield return null;
        }

        if (req.result != UnityWebRequest.Result.Success)
        {
            if (File.Exists(savePath)) File.Delete(savePath);
            onError?.Invoke($"다운로드 실패: {url} — {req.error}");
        }
    }

    private IEnumerator GetText(string url, Action<string> onSuccess, Action<string> onError)
    {
        using var req = UnityWebRequest.Get(url);
        yield return req.SendWebRequest();

        if (req.result != UnityWebRequest.Result.Success)
            onError?.Invoke($"요청 실패: {url} — {req.error}");
        else
            onSuccess?.Invoke(req.downloadHandler.text);
    }

    private static string SongDir(string songId)
        => Path.Combine(CacheRoot, songId);
}
