using System;
using System.Text.Json;

namespace Elfisa.Core;

/// <summary>Текущая сессия пользователя (токен, роль, логин). Сохраняется между запусками.</summary>
public sealed class Session
{
    public static Session Current { get; } = new();

    public string? Token { get; set; }
    public string? Role { get; set; }
    public string? Username { get; set; }

    public bool IsAuthenticated => !string.IsNullOrWhiteSpace(Token);

    /// <summary>Сохранить сессию в настройки (чтобы не логиниться каждый раз).</summary>
    public void Save()
    {
        SettingsStore.Current.Token = Token;
        SettingsStore.Current.Role = Role;
        SettingsStore.Current.Username = Username;
        SettingsStore.Save();
    }

    /// <summary>Восстановить сессию из настроек, если токен есть и не истёк.</summary>
    public static bool TryRestore()
    {
        var s = SettingsStore.Current;
        if (string.IsNullOrWhiteSpace(s.Token) || IsJwtExpired(s.Token))
            return false;
        Current.Token = s.Token;
        Current.Role = s.Role;
        Current.Username = s.Username;
        return true;
    }

    public void Clear()
    {
        Token = null;
        Role = null;
        Username = null;
        SettingsStore.Current.Token = null;
        SettingsStore.Current.Role = null;
        SettingsStore.Current.Username = null;
        SettingsStore.Save();
    }

    /// <summary>Проверяет, истёк ли JWT (по claim exp), с запасом в 1 минуту.</summary>
    internal static bool IsJwtExpired(string token)
    {
        try
        {
            var parts = token.Split('.');
            if (parts.Length != 3) return true;
            var payload = parts[1].Replace('-', '+').Replace('_', '/');
            switch (payload.Length % 4)
            {
                case 2: payload += "=="; break;
                case 3: payload += "="; break;
            }
            var json = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(payload));
            using var doc = JsonDocument.Parse(json);
            if (doc.RootElement.TryGetProperty("exp", out var exp) && exp.TryGetInt64(out var expUnix))
                return DateTimeOffset.UtcNow.ToUnixTimeSeconds() >= expUnix - 60;
            return false; // нет exp — считаем валидным
        }
        catch { return true; }
    }
}
