using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

// 로컬에 다운로드된 곡 목록을 추적하고 persistentDataPath에 저장
public class SongLibrary : MonoBehaviour
{
    public static SongLibrary Instance { get; private set; }

    private const string FileName = "song_library.json";
    private static string SavePath => Path.Combine(Application.persistentDataPath, FileName);

    private LibraryData _data = new LibraryData();

    // ── Unity ────────────────────────────────────────────────

    private void Awake()
    {
        if (Instance != null) { Destroy(gameObject); return; }
        Instance = this;
        DontDestroyOnLoad(gameObject);
        Load();
    }

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

    // 다운로드 완료 시 호출
    public void MarkDownloaded(string songId, string difficulty)
    {
        LibraryEntry entry = GetOrCreate(songId);
        if (!entry.difficulties.Contains(difficulty))
            entry.difficulties.Add(difficulty);
        entry.lastAccessedAt = DateTime.UtcNow.ToString("o");
        Save();
    }

    // 난이도 삭제 시 호출
    public void MarkDifficultyRemoved(string songId, string difficulty)
    {
        LibraryEntry entry = Find(songId);
        if (entry == null) return;

        entry.difficulties.Remove(difficulty);
        if (entry.difficulties.Count == 0)
            _data.entries.Remove(entry);
        Save();
    }

    // 곡 전체 삭제 시 호출
    public void MarkSongRemoved(string songId)
    {
        _data.entries.RemoveAll(e => e.songId == songId);
        Save();
    }

    // 플레이 시작 시 호출 → LRU 갱신
    public void TouchSong(string songId)
    {
        LibraryEntry entry = Find(songId);
        if (entry == null) return;
        entry.lastAccessedAt = DateTime.UtcNow.ToString("o");
        Save();
    }

    public bool IsSongDownloaded(string songId)
        => Find(songId) != null;

    public bool IsDifficultyDownloaded(string songId, string difficulty)
        => Find(songId)?.difficulties.Contains(difficulty) ?? false;

    public List<LibraryEntry> GetAll()
        => _data.entries;

    // 앱 시작 시 실제 파일과 비교해 유효성 검사
    public void ValidateWithFileSystem(DownloadManager dm, List<SongInfo> songs)
    {
        bool dirty = false;
        foreach (SongInfo song in songs)
        {
            LibraryEntry entry = Find(song.id);
            if (entry == null) continue;

            // 오디오 파일이 없으면 항목 전체 제거
            if (!dm.IsSongDownloaded(song.id))
            {
                _data.entries.Remove(entry);
                dirty = true;
                continue;
            }

            // 없어진 난이도 맵 파일 제거
            entry.difficulties.RemoveAll(d => !dm.IsDifficultyDownloaded(song, d));
            if (entry.difficulties.Count == 0)
            {
                _data.entries.Remove(entry);
                dirty = true;
            }
        }
        if (dirty) Save();
    }

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

    private LibraryEntry Find(string songId)
        => _data.entries.Find(e => e.songId == songId);

    private LibraryEntry GetOrCreate(string songId)
    {
        LibraryEntry entry = Find(songId);
        if (entry != null) return entry;

        entry = new LibraryEntry { songId = songId };
        _data.entries.Add(entry);
        return entry;
    }

    private void Load()
    {
        if (!File.Exists(SavePath)) return;
        try
        {
            string json = File.ReadAllText(SavePath);
            _data = JsonUtility.FromJson<LibraryData>(json) ?? new LibraryData();
        }
        catch (Exception e)
        {
            Debug.LogWarning($"[SongLibrary] 로드 실패, 초기화: {e.Message}");
            _data = new LibraryData();
        }
    }

    private void Save()
    {
        File.WriteAllText(SavePath, JsonUtility.ToJson(_data, true));
    }
}

// ── 직렬화 데이터 구조 ─────────────────────────────────────

[Serializable]
public class LibraryData
{
    public List<LibraryEntry> entries = new List<LibraryEntry>();
}

[Serializable]
public class LibraryEntry
{
    public string       songId;
    public List<string> difficulties  = new List<string>();
    public string       lastAccessedAt;
}
