using IWS5.Core.DTO.IAdmin.Schedules;
using IWS5.Core.Enums;
using IWS5.Core.Models;
using IWS5.Core.Services.IAdmin;
using IWS5.DatabaseAccess.Interfaces.IAdmin;
using IWS5.DatabaseAccess.IwsDataModels;

namespace IWS5.Services.IAdminServices;

public class ScheduleTasksService(
    IScheduleTaskRepository taskRepository,
    IScheduleRepository scheduleRepository)
    : IScheduleTasksService
{
    public async Task<CodeResponse<List<ScheduleTaskDTO>>> GetTasksAsync(int scheduleId)
    {
        var schedule = await scheduleRepository.GetByIdAsync(scheduleId);
        if (schedule == null)
            return new CodeResponse<List<ScheduleTaskDTO>>(ResponseCode.NotFound, "Schedule not found");

        var tasks = await taskRepository.ListByScheduleAsync(scheduleId);

        var dtos = tasks.Select(ToDto).ToList();
        return new CodeResponse<List<ScheduleTaskDTO>>(ResponseCode.OK, null, dtos);
    }

    public async Task<CodeResponse<ScheduleTaskDTO>> GetTaskAsync(int taskId)
    {
        var task = await taskRepository.GetByIdAsync(taskId);
        if (task == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.NotFound, "Task not found");

        return new CodeResponse<ScheduleTaskDTO>(ResponseCode.OK, null, ToDto(task));
    }

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

        if (request.OnSuccessActionId.HasValue &&
            await taskRepository.GetTaskActionTypeByIdAsync(request.OnSuccessActionId.Value) == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.BadRequest, "Invalid OnSuccessActionId");

        if (request.OnFailureActionId.HasValue &&
            await taskRepository.GetTaskActionTypeByIdAsync(request.OnFailureActionId.Value) == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.BadRequest, "Invalid OnFailureActionId");

        var entity = new AtscheduledTask
        {
            ScheduleId = scheduleId,
            TaskName = request.TaskName,
            TaskTypeId = request.TaskTypeId,
            CommandText = request.CommandText,
            ExecutablePath = request.ExecutablePath,
            OnSuccessActionId = request.OnSuccessActionId,
            OnFailureActionId = request.OnFailureActionId,
            Enabled = request.Enabled,
            SortOrder = request.SortOrder
        };

        await taskRepository.AddAsync(entity);
        return await GetTaskAsync(entity.TaskId);
    }

    public async Task<CodeResponse<ScheduleTaskDTO>> UpdateTaskAsync(int taskId, ScheduleTaskRequestDTO request)
    {
        var entity = await taskRepository.GetByIdAsync(taskId);
        if (entity == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.NotFound, "Task not found");

        if (request.OnSuccessActionId.HasValue &&
            await taskRepository.GetTaskActionTypeByIdAsync(request.OnSuccessActionId.Value) == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.BadRequest, "Invalid OnSuccessActionId");

        if (request.OnFailureActionId.HasValue &&
            await taskRepository.GetTaskActionTypeByIdAsync(request.OnFailureActionId.Value) == null)
            return new CodeResponse<ScheduleTaskDTO>(ResponseCode.BadRequest, "Invalid OnFailureActionId");

        entity.TaskName = request.TaskName;
        entity.TaskTypeId = request.TaskTypeId;
        entity.CommandText = request.CommandText;
        entity.ExecutablePath = request.ExecutablePath;
        entity.OnSuccessActionId = request.OnSuccessActionId;
        entity.OnFailureActionId = request.OnFailureActionId;
        entity.Enabled = request.Enabled;
        entity.SortOrder = request.SortOrder;

        await taskRepository.UpdateAsync(entity);
        return await GetTaskAsync(taskId);
    }

    public async Task<bool> DeleteTaskAsync(int taskId)
    {
        var entity = await taskRepository.GetByIdAsync(taskId);
        if (entity == null)
            return false;

        await taskRepository.DeleteAsync(entity);
        return true;
    }

    public async Task<bool> RunTaskAsync(int taskId)
        => await taskRepository.RunTaskAsync(taskId);

    public async Task<List<TaskTypeDTO>> GetTaskTypesAsync()
    {
        var types = (await taskRepository.ListTaskTypesAsync())
            .Select(t => new TaskTypeDTO
            {
                TaskTypeId = t.TaskTypeId,
                TaskTypeName = t.TaskTypeName,
                Description = t.Description
            }).ToList();

        return types;
    }

    public async Task<List<TaskActionTypeDTO>> GetTaskActionTypesAsync()
    {
        var actions = await taskRepository.ListTaskActionTypesAsync();

        return actions.Select(a => new TaskActionTypeDTO
        {
            ActionId = a.ActionId,
            ActionName = a.ActionName,
            Description = a.Description
        }).ToList();
    }

    private static ScheduleTaskDTO ToDto(AtscheduledTask t) => new(
        t.TaskId,
        t.TaskName,
        t.TaskType?.TaskTypeName ?? "Unknown",
        t.CommandText,
        t.ExecutablePath,
        t.OnSuccessActionId,
        t.OnFailureActionId,
        t.Enabled,
        t.SortOrder
    );
}
