using System;
using System.Diagnostics;

namespace AsbCloudApp.Data;

/// <summary>
/// Информация о фоновой работе
/// </summary>
public class BackgroundWorkDto
{
    /// <summary>
    /// Идентификатор работы. Должен быть уникальным. Используется в логах и передается в колбэки.
    /// </summary>
    public string Id { get; init; } = null!;

    /// <summary>
    /// Класс описания состояния
    /// </summary>
    public class CurrentStateInfo
    {
        private string state = "start";

        /// <summary>
        /// Время последнего запуска
        /// </summary>
        public DateTime Start { get; } = DateTime.Now;

        /// <summary>
        /// Текущее время выполнения
        /// </summary>
        public TimeSpan ExecutionTime => DateTime.Now - Start;

        /// <summary>
        /// Текстовое описание того, что происходит в задаче.
        /// </summary>
        public string State
        {
            get => state;
            internal set
            {
                state = value;
                StateUpdate = DateTime.Now;
            }
        }

        /// <summary>
        /// Прогресс
        /// </summary>
        public double Progress { get; internal set; } = 0;

        /// <summary>
        /// Время последнего запуска
        /// </summary>
        public DateTime StateUpdate { get; private set; } = DateTime.Now;
    }

    /// <summary>
    /// Инфо о последней ошибке
    /// </summary>
    public class LastErrorInfo : LastCompleteInfo
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        /// <param name="errorText"></param>
        public LastErrorInfo(CurrentStateInfo state, string errorText)
            : base(state)
        {
            ErrorText = errorText;
        }

        /// <summary>
        /// Последняя ошибка
        /// </summary>
        public string ErrorText { get; init; } = null!;
    }

    /// <summary>
    /// Инфо о последнем завершении
    /// </summary>
    public class LastCompleteInfo
    {
        /// <summary>
        /// Дата запуска
        /// </summary>
        public DateTime Start { get; init; }

        /// <summary>
        /// Дата завершения
        /// </summary>
        public DateTime End { get; init; }

        /// <summary>
        /// Продолжительность последнего выполнения
        /// </summary>
        public TimeSpan ExecutionTime => End - Start;

        /// <summary>
        /// Состояние на момент завершения
        /// </summary>
        public string State { get; init; }

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="state"></param>
        public LastCompleteInfo(CurrentStateInfo state)
        {
            Start = state.Start;
            End = DateTime.Now;
            State = state.State;
        }
    }

    /// <summary>
    /// Текущее состояние
    /// </summary>
    public CurrentStateInfo? CurrentState { get; private set; }

    /// <summary>
    /// Последняя ошибка
    /// </summary>
    public LastErrorInfo? LastError { get; private set; }

    /// <summary>
    /// Последняя завершенная
    /// </summary>
    public LastCompleteInfo? LastComplete { get; private set; }

    /// <summary>
    /// Кол-во запусков
    /// </summary>
    public int CountStart { get; private set; }

    /// <summary>
    /// Кол-во завершений
    /// </summary>
    public int CountComplete { get; private set; }

    /// <summary>
    /// Кол-во ошибок
    /// </summary>
    public int CountErrors { get; private set; }

    /// <summary>
    /// Максимально допустимое время выполнения работы
    /// </summary>
    public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(1);

    private string WorkNameForTrace => $"Backgroud work:\"{Id}\"";

    /// <summary>
    /// Обновления состояния при запуске работы
    /// </summary>
    protected void SetStatusStart()
    {
        CurrentState = new();
        CountStart++;
        Trace.TraceInformation($"{WorkNameForTrace} state: starting");
    }

    /// <summary>
    /// Обновления состояния в процессе работы
    /// </summary>
    protected void UpdateStatus(string newState, double? progress)
    {
        if (CurrentState is null)
            return;

        CurrentState.State = newState;
        if (progress.HasValue)
            CurrentState.Progress = progress.Value;

        Trace.TraceInformation($"{WorkNameForTrace} state[{100*progress:#}%]: {newState}");
    }

    /// <summary>
    /// Обновления состояния при успешном завершении работы
    /// </summary>
    protected void SetStatusComplete()
    {
        CountComplete++;
        if (CurrentState is null)
            return;

        LastComplete = new(CurrentState);
        CurrentState = null;
        Trace.TraceInformation($"{WorkNameForTrace} state: completed");
    }

    /// <summary>
    /// Обновления состояния при ошибке в работе
    /// </summary>
    protected void SetLastError(string errorMessage)
    {
        CountErrors++;
        if (CurrentState is null)
            return;

        LastError = new LastErrorInfo(CurrentState, errorMessage);
        CurrentState = null;
        Trace.TraceError($"{WorkNameForTrace} throw exception[{CountErrors}]: {errorMessage}");
    }
}