using System;
using EventsAppQuest.Core;
using UnityEngine;

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Persistência local simulada da sessão Quest: salvar/restaurar/limpar snapshot em PlayerPrefs.
    /// Prepara retomada da apresentação e futura persistência real; sem backend nem persistência remota.
    /// </summary>
    public class QuestSessionLocalPersistenceController : MonoBehaviour
    {
        private const string PrefsKey = "QuestSessionLocalSnapshot";
        private QuestPresentationSession _session;
        private Func<string> _getProjectId;

        /// <summary>Snapshot actual em memória (último salvo ou restaurado para exibição); pode ser null.</summary>
        public QuestSessionLocalSnapshot CurrentSnapshot => _session?.CurrentLocalSnapshot;

        /// <summary>True se existir um snapshot válido em storage para restaurar.</summary>
        public bool HasRestorableSnapshot()
        {
            try
            {
                return PlayerPrefs.HasKey(PrefsKey) && !string.IsNullOrEmpty(PlayerPrefs.GetString(PrefsKey));
            }
            catch
            {
                return false;
            }
        }

        /// <summary>Liga o controlador à sessão.</summary>
        public void Bind(QuestPresentationSession session)
        {
            _session = session;
        }

        /// <summary>Regista getter opcional para ProjectId (ex.: () => AppSession.CurrentProject?.Id).</summary>
        public void SetProjectIdGetter(Func<string> getProjectId)
        {
            _getProjectId = getProjectId;
        }

        /// <summary>Salva o estado actual da sessão num snapshot e persiste localmente (PlayerPrefs).</summary>
        public void Save()
        {
            if (_session == null) return;
            try
            {
                var projectId = _getProjectId != null ? _getProjectId() : null;
                var proposalId = _session.Proposal?.Id;
                var sessionId = _session.CurrentCommercialOutcome?.SessionId ?? _session.CurrentExportPayload?.SessionId ?? ("Quest_" + DateTime.UtcNow.ToString("yyyyMMddHHmmss"));
                var snapshot = new QuestSessionLocalSnapshot
                {
                    SessionId = sessionId ?? "",
                    ProjectId = projectId ?? "",
                    ActiveProposalId = proposalId ?? "",
                    RuntimeMode = _session.RuntimeMode,
                    NavigationMode = _session.NavigationMode,
                    CurrentGuidedStepIndex = _session.CurrentGuidedStepIndex,
                    CurrentHotspotIndex = _session.CurrentHotspotIndex,
                    CurrentSceneStateIndex = _session.CurrentSceneStateIndex,
                    IsClosingOpen = _session.HasClosingOpen,
                    LastDecisionState = _session.LastDecisionState,
                    LastConfirmedCTA = _session.LastConfirmedCTA ?? "",
                    HasCommercialOutcome = _session.CurrentCommercialOutcome != null,
                    HasExportPayload = _session.CurrentExportPayload != null,
                    SavedAt = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")
                };
                var json = JsonUtility.ToJson(snapshot);
                PlayerPrefs.SetString(PrefsKey, json);
                PlayerPrefs.Save();
                _session.CurrentLocalSnapshot = snapshot;
            }
            catch (Exception)
            {
                // Fallback: não quebrar a apresentação
            }
        }

        /// <summary>Restaura o snapshot do storage para a sessão. Retorna true se restaurou; aplica índices, modo e decisão. Chamar onRestoreClosing(true) se snapshot tinha closing aberto.</summary>
        public bool Restore(Action<bool> onRestoreClosing = null)
        {
            if (_session == null) return false;
            try
            {
                if (!PlayerPrefs.HasKey(PrefsKey)) return false;
                var json = PlayerPrefs.GetString(PrefsKey);
                if (string.IsNullOrEmpty(json)) return false;
                var snapshot = JsonUtility.FromJson<QuestSessionLocalSnapshot>(json);
                if (snapshot == null) return false;

                var stepCount = _session.GuidedSteps?.Count ?? 0;
                var hotspotCount = _session.Hotspots?.Count ?? 0;
                var stateCount = _session.SceneStates?.Count ?? 0;

                _session.CurrentGuidedStepIndex = Math.Max(0, Math.Min(snapshot.CurrentGuidedStepIndex, stepCount > 0 ? stepCount - 1 : 0));
                _session.CurrentHotspotIndex = snapshot.CurrentHotspotIndex < 0 || hotspotCount == 0 ? -1 : Math.Min(snapshot.CurrentHotspotIndex, hotspotCount - 1);
                _session.CurrentSceneStateIndex = snapshot.CurrentSceneStateIndex < 0 || stateCount == 0 ? -1 : Math.Min(snapshot.CurrentSceneStateIndex, stateCount - 1);
                _session.NavigationMode = snapshot.NavigationMode;
                _session.LastDecisionState = snapshot.LastDecisionState;
                _session.LastConfirmedCTA = string.IsNullOrEmpty(snapshot.LastConfirmedCTA) ? null : snapshot.LastConfirmedCTA;
                _session.CurrentLocalSnapshot = snapshot;
                _session.LastRestoreTimestamp = DateTime.UtcNow;

                onRestoreClosing?.Invoke(snapshot.IsClosingOpen);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>Remove o snapshot do storage e limpa CurrentLocalSnapshot na sessão.</summary>
        public void Clear()
        {
            try
            {
                PlayerPrefs.DeleteKey(PrefsKey);
                PlayerPrefs.Save();
                if (_session != null)
                    _session.CurrentLocalSnapshot = null;
            }
            catch (Exception)
            {
                // Fallback
            }
        }
    }
}
