using System;

namespace MajacloudSdk.Internal
{
    internal sealed class SessionData
    {
        public string AccessToken;
        public long AccessExpiresAtUnix;
        public string RefreshToken;
        public long RefreshExpiresAtUnix;
        public string PlayerJson;
        public string AuthMethod;

        public bool AccessExpiresWithin(float seconds) => AccessExpiresAtUnix - NowUnix() <= seconds;
        public bool RefreshExpired => RefreshExpiresAtUnix <= NowUnix();

        public static long NowUnix() => DateTimeOffset.UtcNow.ToUnixTimeSeconds();

        public static SessionData FromResponse(JsonNode json)
        {
            var now = NowUnix();
            return new SessionData
            {
                AccessToken = json.GetString("access_token"),
                AccessExpiresAtUnix = now + json.GetLong("expires_in", 3600),
                RefreshToken = json.GetString("refresh_token"),
                RefreshExpiresAtUnix = now + json.GetLong("refresh_expires_in", 2592000),
                PlayerJson = json.GetObject("player").IsNull ? null : json.GetObject("player").ToJson(),
                AuthMethod = json.GetString("auth_method"),
            };
        }

        public string Serialize()
        {
            return JsonNode.Object()
                .Set("access_token", AccessToken)
                .Set("access_expires_at", AccessExpiresAtUnix)
                .Set("refresh_token", RefreshToken)
                .Set("refresh_expires_at", RefreshExpiresAtUnix)
                .Set("player", PlayerJson != null ? JsonNode.Raw(PlayerJson) : JsonNode.Null)
                .Set("auth_method", AuthMethod)
                .ToJson();
        }

        public static SessionData Deserialize(string json)
        {
            if (string.IsNullOrEmpty(json) || !JsonNode.TryParse(json, out var node, out _) || !node.IsObject) return null;
            var data = new SessionData
            {
                AccessToken = node.GetString("access_token"),
                AccessExpiresAtUnix = node.GetLong("access_expires_at"),
                RefreshToken = node.GetString("refresh_token"),
                RefreshExpiresAtUnix = node.GetLong("refresh_expires_at"),
                PlayerJson = node.GetObject("player").IsNull ? null : node.GetObject("player").ToJson(),
                AuthMethod = node.GetString("auth_method"),
            };
            return string.IsNullOrEmpty(data.RefreshToken) ? null : data;
        }
    }

    /// <summary>Persists the session (obfuscated) per project.</summary>
    internal sealed class SessionStore
    {
        private readonly IMajacloudStorage _storage;
        private readonly string _projectId;
        private readonly string _key;

        public SessionStore(IMajacloudStorage storage, string projectId, string deviceId)
        {
            _storage = storage;
            _projectId = projectId;
            _key = deviceId + "|" + projectId;
        }

        public SessionData Load()
        {
            var stored = _storage.GetString(StorageKeys.Session(_projectId));
            if (string.IsNullOrEmpty(stored)) return null;
            var plain = Obfuscator.Unprotect(stored, _key);
            var data = SessionData.Deserialize(plain);
            if (data == null) Clear();
            return data;
        }

        public void Save(SessionData data)
        {
            _storage.SetString(StorageKeys.Session(_projectId), Obfuscator.Protect(data.Serialize(), _key));
            _storage.Flush();
        }

        public void Clear()
        {
            _storage.Delete(StorageKeys.Session(_projectId));
            _storage.Flush();
        }
    }
}
