using Contime.data;
using System.Diagnostics;

namespace Contime.model {
    public class TimeTrackerModel {
        // --- Public State & Data ---
        public enum AppState { Idle, WorkdayActive, TaskActive, OutOfContext }
        public AppState CurrentState { get; private set; } = AppState.Idle;
        public List<TaskItem> Tasks { get; private set; } = new List<TaskItem>();
        public TaskItem SelectedTask { get; private set; }
        public string OutOfContextReason { get; set; } = "";
        public DataAccess DataAccess => _dataAccess;

        // --- Public Read-only Timer Properties ---
        public TimeSpan WorkdayTime => _workdayStopwatch.Elapsed;
        public TimeSpan ActiveTaskTime => _activeTaskStopwatch.Elapsed;
        public TimeSpan IdleTime => _idleStopwatch.Elapsed;
        public TimeSpan SelectedTaskTotalTime => SelectedTask?.ElapsedTime ?? TimeSpan.Zero;
        public TimeSpan DayTotal { get; private set; } = TimeSpan.Zero;
        public TimeSpan WeekTotal { get; private set; } = TimeSpan.Zero;


        // --- Events ---
        public event Action StateChanged; // For high-frequency updates (timers)
        public event Action MajorStateChanged; // For low-frequency updates (task list)

        // --- Private Fields ---
        private readonly DataAccess _dataAccess;
        private readonly Stopwatch _workdayStopwatch = new Stopwatch();
        private readonly Stopwatch _activeTaskStopwatch = new Stopwatch();
        private readonly Stopwatch _idleStopwatch = new Stopwatch();
        private long _currentWorkdayId;
        private long _currentTaskTimeId;

        public TimeTrackerModel(DataAccess dataAccess) {
            _dataAccess = dataAccess;
            ReloadAllData(); // Initial load
        }

        private void ReloadAllData() {
            long? selectedTaskId = SelectedTask?.Id;

            Tasks = _dataAccess.GetAllTasks();
            DayTotal = _dataAccess.GetTotalTimeForDate(DateTime.Today);
            WeekTotal = _dataAccess.GetTotalTimeForCurrentWeek();

            if (selectedTaskId.HasValue) {
                SelectedTask = Tasks.FirstOrDefault(t => t.Id == selectedTaskId.Value);
            }

            MajorStateChanged?.Invoke();
        }

        // --- Public Methods (State Changers) ---

        public void StartStopWorkday() {
            if (CurrentState == AppState.Idle) {
                _currentWorkdayId = _dataAccess.GetOrCreateWorkday(DateTime.Today);
                CurrentState = AppState.WorkdayActive;
                _workdayStopwatch.Restart();
                _idleStopwatch.Restart();
            }
            else {
                if (CurrentState == AppState.TaskActive) StopTask();
                CurrentState = AppState.Idle;
                _workdayStopwatch.Stop();
                _idleStopwatch.Stop();
                SelectedTask = null;
            }
            ReloadAllData();
        }

        public void SelectTask(long taskId) {
            if (SelectedTask?.Id == taskId) return; // Prevent re-selection loop

            SelectedTask = taskId == -1 ? null : Tasks.FirstOrDefault(t => t.Id == taskId);

            // A selection change is a major state change that affects buttons
            MajorStateChanged?.Invoke();
        }

        public void StartStopTask() {
            if (CurrentState == AppState.TaskActive) // Stopping
            {
                StopTask();
            }
            else if (CurrentState == AppState.WorkdayActive && SelectedTask != null && SelectedTask.Status == "open") // Starting
            {
                _currentTaskTimeId = _dataAccess.StartTaskTime(SelectedTask.Id, _currentWorkdayId);
                CurrentState = AppState.TaskActive;
                _activeTaskStopwatch.Restart();
                _idleStopwatch.Stop();
                _idleStopwatch.Reset();
            }
            ReloadAllData();
        }

        public void SwitchContext() {
            if (CurrentState == AppState.OutOfContext) // Returning
            {
                CurrentState = _currentTaskTimeId > 0 ? AppState.TaskActive : AppState.WorkdayActive;
                _workdayStopwatch.Start();
                if (CurrentState == AppState.TaskActive) _activeTaskStopwatch.Start();
                else _idleStopwatch.Start();
            }
            else if (CurrentState != AppState.Idle) // Going
            {
                _workdayStopwatch.Stop();
                if (CurrentState == AppState.TaskActive) _activeTaskStopwatch.Stop();
                if (CurrentState == AppState.WorkdayActive) _idleStopwatch.Stop();
                CurrentState = AppState.OutOfContext;
            }
            StateChanged?.Invoke();
        }

        public void AddTask(string name) {
            if (string.IsNullOrWhiteSpace(name)) return;
            _dataAccess.AddTask(name);
            ReloadAllData();
        }

        public void ToggleSelectedTaskStatus() {
            if (SelectedTask == null || CurrentState == AppState.TaskActive) return;

            string newStatus = SelectedTask.Status == "open" ? "closed" : "open";
            _dataAccess.UpdateTaskStatus(SelectedTask.Id, newStatus, newStatus == "closed");
            ReloadAllData();
        }

        private void StopTask() {
            if (!_activeTaskStopwatch.IsRunning) return;

            _dataAccess.EndTaskTime(_currentTaskTimeId);
            _currentTaskTimeId = 0;

            CurrentState = AppState.WorkdayActive;
            _activeTaskStopwatch.Stop();
            _activeTaskStopwatch.Reset();
            _idleStopwatch.Restart();
        }
    }
}

