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

// Synology DSM File Station API를 통해 NAS에 파일 업로드 및 songs.json 갱신
public class NasPublisher : MonoBehaviour
{
    [Header("NAS 접속 정보")]
    [SerializeField] private string nasBaseUrl  = "http://192.168.55.3:5000"; // DSM 포트 (내부망)
    [SerializeField] private string nasAccount  = "admin";
    [SerializeField] private string nasPassword = ""; // Inspector에서 입력
    [SerializeField] private string nasRootPath = "/web/beatsaber";          // NAS 내 절대경로

    [Header("정적 서버 URL (songs.json 읽기용)")]
    [SerializeField] private string staticBaseUrl = "http://whdwo798.synology.me:8180/beatsaber";

    private string _sid = ""; // DSM 세션 ID

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

    public IEnumerator Publish(
        SongInfo song,
        string audioPath,
        Dictionary<string, List<NoteData>> maps,
        Action<float> onProgress,
        Action onComplete,
        Action<string> onError)
    {
        // 1단계: DSM 로그인
        yield return Login(onError);
        if (string.IsNullOrEmpty(_sid)) yield break;
        onProgress?.Invoke(0.1f);

        // 2단계: 오디오 업로드
        yield return UploadFile(
            audioPath,
            $"{nasRootPath}/music",
            $"{song.id}.mp3",
            onError);
        onProgress?.Invoke(0.4f);

        // 3단계: 각 난이도 맵 JSON 업로드
        int total = maps.Count;
        int done  = 0;

        foreach (var kv in maps)
        {
            string fileName = $"Map_{song.id}_{kv.Key}.json";
            string json     = BeatSageConverter.ToMapJson(kv.Value);
            byte[] bytes    = Encoding.UTF8.GetBytes(json);

            // 파일명에 맞춰 DifficultyInfo 업데이트
            AssignMapFile(song, kv.Key, fileName);

            yield return UploadBytes(
                bytes, fileName,
                $"{nasRootPath}/maps",
                onError);

            done++;
            onProgress?.Invoke(0.4f + (float)done / total * 0.3f);
        }

        // 4단계: songs.json 다운로드 → 항목 추가 → 재업로드
        yield return PatchSongsJson(song, onError);
        onProgress?.Invoke(0.95f);

        // 5단계: 로그아웃
        yield return Logout();

        onProgress?.Invoke(1f);
        onComplete?.Invoke();
        Debug.Log($"[NasPublisher] '{song.title}' NAS 업로드 완료");
    }

    // ── DSM 인증 ─────────────────────────────────────────────

    private IEnumerator Login(Action<string> onError)
    {
        string url = $"{nasBaseUrl}/webapi/auth.cgi" +
                     $"?api=SYNO.API.Auth&version=3&method=login" +
                     $"&account={UnityWebRequest.EscapeURL(nasAccount)}" +
                     $"&passwd={UnityWebRequest.EscapeURL(nasPassword)}" +
                     $"&session=FileStation&format=sid";

        using var req = UnityWebRequest.Get(url);
        yield return req.SendWebRequest();

        if (req.result != UnityWebRequest.Result.Success)
        {
            onError?.Invoke($"DSM 로그인 실패: {req.error}");
            yield break;
        }

        _sid = ParseSid(req.downloadHandler.text);
        if (string.IsNullOrEmpty(_sid))
            onError?.Invoke("DSM sid 파싱 실패 — 계정 정보를 확인하세요");
    }

    private IEnumerator Logout()
    {
        string url = $"{nasBaseUrl}/webapi/auth.cgi" +
                     $"?api=SYNO.API.Auth&version=1&method=logout&session=FileStation&_sid={_sid}";
        using var req = UnityWebRequest.Get(url);
        yield return req.SendWebRequest();
        _sid = "";
    }

    // ── 파일 업로드 ───────────────────────────────────────────

    private IEnumerator UploadFile(string localPath, string nasFolder,
        string fileName, Action<string> onError)
    {
        byte[] bytes = File.ReadAllBytes(localPath);
        yield return UploadBytes(bytes, fileName, nasFolder, onError);
    }

    private IEnumerator UploadBytes(byte[] bytes, string fileName,
        string nasFolder, Action<string> onError)
    {
        string url = $"{nasBaseUrl}/webapi/entry.cgi";

        var form = new List<IMultipartFormSection>
        {
            new MultipartFormDataSection("api",       "SYNO.FileStation.Upload"),
            new MultipartFormDataSection("version",   "2"),
            new MultipartFormDataSection("method",    "upload"),
            new MultipartFormDataSection("path",      nasFolder),
            new MultipartFormDataSection("overwrite", "true"),
            new MultipartFormDataSection("_sid",      _sid),
            new MultipartFormFileSection("file", bytes, fileName, "application/octet-stream"),
        };

        using var req = UnityWebRequest.Post(url, form);
        yield return req.SendWebRequest();

        if (req.result != UnityWebRequest.Result.Success)
            onError?.Invoke($"업로드 실패({fileName}): {req.error}");
        else
            Debug.Log($"[NasPublisher] 업로드 완료: {fileName}");
    }

    // ── songs.json 패치 ───────────────────────────────────────

    private IEnumerator PatchSongsJson(SongInfo newSong, Action<string> onError)
    {
        // 현재 songs.json 가져오기 (정적 서버에서 읽음)
        SongsList songsList = null;

        using (var req = UnityWebRequest.Get($"{staticBaseUrl}/songs.json"))
        {
            yield return req.SendWebRequest();

            if (req.result == UnityWebRequest.Result.Success)
            {
                songsList = JsonUtility.FromJson<SongsList>(req.downloadHandler.text);
            }
        }

        if (songsList == null)
            songsList = new SongsList { version = "1.0", songs = new System.Collections.Generic.List<SongInfo>() };

        // 같은 id가 이미 있으면 교체, 없으면 추가
        int existingIdx = songsList.songs.FindIndex(s => s.id == newSong.id);
        if (existingIdx >= 0)
            songsList.songs[existingIdx] = newSong;
        else
            songsList.songs.Add(newSong);

        // 수정된 songs.json 업로드
        byte[] jsonBytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson(songsList, true));
        yield return UploadBytes(jsonBytes, "songs.json", nasRootPath, onError);
    }

    // ── 유틸 ─────────────────────────────────────────────────

    private static string ParseSid(string json)
    {
        const string key = "\"sid\":\"";
        int start = json.IndexOf(key, StringComparison.Ordinal);
        if (start < 0) return null;
        start += key.Length;
        int end = json.IndexOf('"', start);
        return end > start ? json.Substring(start, end - start) : null;
    }

    private static void AssignMapFile(SongInfo song, string difficulty, string fileName)
    {
        var info = song.difficulties.Get(difficulty);
        if (info != null) info.mapFile = $"maps/{fileName}";
    }
}
