using Cronos;
using IWS5.Core.DTO.IAdmin.Schedules;
using IWS5.Core.Enums;
using IWS5.Core.Enums.IAdmin;
using IWS5.Core.Models;
using IWS5.Core.Services.IAdmin;
using IWS5.DatabaseAccess.Interfaces.IAdmin;
using IWS5.DatabaseAccess.IwsDataModels;
using Serilog;
using System.Text.RegularExpressions;

namespace IWS5.Services.IAdminServices;

public class SchedulesService(IScheduleRepository scheduleRepository, IScheduleTaskRepository taskRepository, ILogger logger)
    : ISchedulesService
{
    public async Task<CodeResponse<List<ScheduleListItemDTO>>> GetSchedulesAsync()
    {
        var schedules = await scheduleRepository.ListAsync();

        var dtos = schedules.Select(s => new ScheduleListItemDTO(
            s.ScheduleId,
            s.Name,
            s.Server.HostName,
            s.Description,
            s.Enabled,
            s.Priority ?? 0,
            s.ScheduleType?.ScheduleTypeName ?? "Unknown",
            s.ScheduleType?.ScheduleTypeId ?? 0,
            s.Status.StatusName,
            s.LastRun,
            s.ScheduleType?.ScheduleTypeId == (int)Schedule.Recurring ? CronExpression.Parse(s.RecurrenceExpression).GetNextOccurrence(DateTime.UtcNow) : null,
            s.LastRunStatus?.StatusName
        )).ToList();

        return new CodeResponse<List<ScheduleListItemDTO>>(ResponseCode.OK, null, dtos);
    }

    public async Task<CodeResponse<ScheduleDetailsDTO>> GetScheduleDetailsAsync(int scheduleId)
    {
        var schedule = await scheduleRepository.GetByIdAsync(scheduleId);
        if (schedule == null)
            return new CodeResponse<ScheduleDetailsDTO>(ResponseCode.NotFound, "Schedule not found");

        var tasks = schedule.AtscheduledTasks.Select(t => new ScheduleTaskDTO(
            t.TaskId,
            t.TaskName,
            t.TaskType?.TaskTypeName ?? "Unknown",
            t.CommandText,
            t.ExecutablePath,
            t.OnSuccessActionId,
            t.OnFailureActionId,
            t.Enabled,
            t.SortOrder
        )).ToList();

        var dto = new ScheduleDetailsDTO(
            schedule.ScheduleId,
            schedule.Name,
            schedule.Server.HostName,
            schedule.Description,
            schedule.Enabled,
            schedule.Priority ?? 0,
            schedule.WaitForCompletion,
            schedule.ScheduleType?.ScheduleTypeName ?? "Unknown",
            schedule.ScheduleType?.ScheduleTypeId ?? 0,
            schedule.Status.StatusName,
            schedule.LastRun,
            schedule.ScheduleType?.ScheduleTypeId == (int)Schedule.Recurring ? CronExpression.Parse(schedule.RecurrenceExpression).GetNextOccurrence(DateTime.UtcNow) : null,
            schedule.LastRunStatus?.StatusName,
            tasks,
            schedule.RecurrenceExpression,
            schedule.StartTime,
            schedule.ExpireTime,
            schedule.CreatedAt,
            schedule.UpdatedAt
        );

        return new CodeResponse<ScheduleDetailsDTO>(ResponseCode.OK, null, dto);
    }

    public async Task<CodeResponse<ScheduleDetailsDTO>> CreateScheduleAsync(ScheduleCreateRequestDTO request)
    {
        var entity = new AtscheduledItem
        {
            Name = request.Name,
            Description = request.Description,
            Enabled = request.Enabled,
            WaitForCompletion = request.WaitForCompletion,
            Priority = request.Priority,
            ScheduleTypeId = request.ScheduleTypeId,

            RecurrenceExpression = request.RecurrenceExpression,
            StartTime = request.StartTime,
            ExpireTime = request.ExpireTime,

            StatusId = 1, // Pending
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };

        await scheduleRepository.AddAsync(entity);

        return await GetScheduleDetailsAsync(entity.ScheduleId);
    }

    public async Task<CodeResponse<ScheduleDetailsDTO>> UpdateScheduleAsync(int scheduleId, ScheduleUpdateRequestDTO request)
    {
        var entity = await scheduleRepository.GetByIdAsync(scheduleId);
        if (entity == null)
            return new CodeResponse<ScheduleDetailsDTO>(ResponseCode.NotFound, "Schedule not found");

        entity.Name = request.Name;
        entity.ServerHost = request.ServerHost;
        entity.Description = request.Description;
        entity.Enabled = request.Enabled;
        entity.WaitForCompletion = request.WaitForCompletion;
        entity.Priority = request.Priority;
        entity.StatusId = request.StatusId;
        entity.ScheduleTypeId = request.ScheduleTypeId;
        entity.RecurrenceExpression = request.RecurrenceExpression;
        entity.StartTime = request.StartTime;
        entity.ExpireTime = request.ExpireTime;
        entity.UpdatedAt = DateTime.UtcNow;

        await scheduleRepository.UpdateAsync(entity);
        return await GetScheduleDetailsAsync(scheduleId);
    }

    public async Task<bool> DeleteScheduleAsync(int scheduleId)
    {
        var schedule = await scheduleRepository.GetByIdAsync(scheduleId);
        if (schedule == null)
            return false;

        await scheduleRepository.DeleteAsync(schedule);
        return true;
    }

    public async Task<bool> UpdateStatusAsync(int scheduleId, bool enabled, int statusId)
        => await scheduleRepository.UpdateStatusAsync(scheduleId, enabled, statusId);

    public async Task<bool> RunScheduleAsync(int scheduleId)
        => await scheduleRepository.RunScheduleAsync(scheduleId);

    public async Task<List<ScheduleTypeDTO>> ListScheduleTypesAsync()
    {
        var types = await scheduleRepository.ListScheduleTypesAsync();
        return types.Select(t => new ScheduleTypeDTO(t.ScheduleTypeId, t.ScheduleTypeName)).ToList();
    }

    public async Task<ScheduleTypeDTO?> GetScheduleTypeByIdAsync(int scheduleTypeId)
    {
        var type = await scheduleRepository.GetScheduleTypeByIdAsync(scheduleTypeId);
        if (type == null) return null;
        return new ScheduleTypeDTO(type.ScheduleTypeId, type.ScheduleTypeName);
    }
}
