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

// 앱 시작 시 캐시 총 용량을 확인하고 1GB 초과 시 LRU 순으로 자동 삭제
public class CacheManager : MonoBehaviour
{
    private const long MaxCacheBytes = 1L * 1024 * 1024 * 1024; // 1 GB

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

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

    private void Start()
    {
        RunEviction();
    }

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

    public long TotalCacheBytes()
    {
        if (!Directory.Exists(CacheRoot)) return 0;
        return Directory.GetFiles(CacheRoot, "*", SearchOption.AllDirectories)
                        .Sum(f => new FileInfo(f).Length);
    }

    // 강제 정리 (UI에서 수동 호출용)
    public void RunEviction()
    {
        if (!Directory.Exists(CacheRoot)) return;

        long total = TotalCacheBytes();
        if (total <= MaxCacheBytes)
        {
            Debug.Log($"[CacheManager] 용량 정상: {FormatBytes(total)}");
            return;
        }

        // 곡 폴더를 마지막 접근 시간 오름차순 정렬 (가장 오래된 것부터)
        List<SongDirInfo> dirs = GetSongDirs();
        dirs.Sort((a, b) => a.lastAccessed.CompareTo(b.lastAccessed));

        foreach (SongDirInfo dir in dirs)
        {
            if (total <= MaxCacheBytes) break;

            total -= dir.sizeBytes;
            Directory.Delete(dir.path, recursive: true);
            SongLibrary.Instance?.MarkSongRemoved(dir.songId);
            Debug.Log($"[CacheManager] LRU 삭제: {dir.songId} ({FormatBytes(dir.sizeBytes)})");
        }

        Debug.Log($"[CacheManager] 정리 완료 → 현재 {FormatBytes(total)}");
    }

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

    private List<SongDirInfo> GetSongDirs()
    {
        var result = new List<SongDirInfo>();

        foreach (string dir in Directory.GetDirectories(CacheRoot))
        {
            long size = Directory.GetFiles(dir, "*", SearchOption.AllDirectories)
                                 .Sum(f => new FileInfo(f).Length);

            // 마지막 접근 시간은 SongLibrary 기록 우선, 없으면 파일시스템 참조
            DateTime lastAccessed = DateTime.MaxValue;
            string songId = Path.GetFileName(dir);
            LibraryEntry entry = SongLibrary.Instance?.GetAll()
                                            .Find(e => e.songId == songId);
            if (entry != null && DateTime.TryParse(entry.lastAccessedAt, out DateTime t))
                lastAccessed = t;
            else
                lastAccessed = Directory.GetLastAccessTimeUtc(dir);

            result.Add(new SongDirInfo
            {
                songId       = songId,
                path         = dir,
                sizeBytes    = size,
                lastAccessed = lastAccessed
            });
        }

        return result;
    }

    private static string FormatBytes(long bytes)
    {
        if (bytes >= 1024 * 1024 * 1024) return $"{bytes / (1024f * 1024 * 1024):F2} GB";
        if (bytes >= 1024 * 1024)        return $"{bytes / (1024f * 1024):F1} MB";
        return $"{bytes / 1024f:F0} KB";
    }

    private struct SongDirInfo
    {
        public string   songId;
        public string   path;
        public long     sizeBytes;
        public DateTime lastAccessed;
    }
}
