using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Data;
using Haoliang.Data.Entities;
using Haoliang.Models.System;
using Haoliang.Data.Repositories;

namespace Haoliang.Data.Repositories
{
    public interface IScheduledTaskRepository : IRepository<ScheduledTask>
    {
        Task<IEnumerable<ScheduledTask>> GetActiveTasksAsync();
        Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(Haoliang.Models.System.TaskStatus status);
        Task<TaskExecutionResult> GetLastExecutionResultAsync(string taskId);
        Task<IEnumerable<ScheduledTask>> GetTasksByCronExpressionAsync(string cronExpression);
        Task<IEnumerable<ScheduledTask>> GetOverdueTasksAsync();
        Task<bool> ExecuteTaskAsync(string taskId);
        Task<ScheduledTask> GetNextScheduledTaskAsync();
        Task<TaskExecutionSummary> GetExecutionSummaryAsync(DateTime date);
        Task<IEnumerable<TaskExecutionResult>> GetExecutionHistoryAsync(string taskId, int count = 10);
    }

    public class ScheduledTaskRepository : Repository<ScheduledTask>, IScheduledTaskRepository
    {
        private readonly CNCDbContext _context;

        public ScheduledTaskRepository(CNCDbContext context) : base(context)
        {
            _context = context;
        }

        public async Task<IEnumerable<ScheduledTask>> GetActiveTasksAsync()
        {
            return await _context.ScheduledTasks
                .Where(t => t.IsActive && t.TaskStatus != Haoliang.Models.System.TaskStatus.Disabled)
                .OrderBy(t => t.NextRunTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(Haoliang.Models.System.TaskStatus status)
        {
            return await _context.ScheduledTasks
                .Where(t => t.TaskStatus == status)
                .OrderBy(t => t.CreatedAt)
                .ToListAsync();
        }

        public async Task<TaskExecutionResult> GetLastExecutionResultAsync(string taskId)
        {
            return await _context.TaskExecutionResults
                .Where(r => r.TaskId == taskId)
                .OrderByDescending(r => r.ExecutionTime)
                .FirstOrDefaultAsync();
        }

        public async Task<IEnumerable<ScheduledTask>> GetTasksByCronExpressionAsync(string cronExpression)
        {
            return await _context.ScheduledTasks
                .Where(t => t.CronExpression == cronExpression && t.IsActive)
                .OrderBy(t => t.TaskName)
                .ToListAsync();
        }

        public async Task<IEnumerable<ScheduledTask>> GetOverdueTasksAsync()
        {
            var now = DateTime.Now;
            return await _context.ScheduledTasks
                .Where(t => t.IsActive && 
                           t.NextRunTime <= now && 
                           t.TaskStatus != Haoliang.Models.System.TaskStatus.Running)
                .OrderBy(t => t.NextRunTime)
                .ToListAsync();
        }

        public async Task<bool> ExecuteTaskAsync(string taskId)
        {
            var task = await _context.ScheduledTasks.Where(t => t.TaskId == taskId).FirstOrDefaultAsync();
            if (task == null || !task.IsActive)
            {
                return false;
            }

            task.TaskStatus = Haoliang.Models.System.TaskStatus.Running;
            task.LastRunAt = DateTime.Now;
            await SaveAsync();

            // Create execution result
            var result = new TaskExecutionResult
            {
                TaskId = taskId,
                ExecutionTime = DateTime.Now,
                Status = Haoliang.Models.System.TaskStatus.Running,
                ErrorMessage = null
            };

            _context.TaskExecutionResults.Add(result);
            await SaveAsync();

            return true;
        }

        public async Task<ScheduledTask> GetNextScheduledTaskAsync()
        {
            var now = DateTime.Now;
            return await _context.ScheduledTasks
                .Where(t => t.IsActive && 
                           t.NextRunTime <= now && 
                           t.TaskStatus != Haoliang.Models.System.TaskStatus.Running)
                .OrderBy(t => t.NextRunTime)
                .FirstOrDefaultAsync();
        }

        public async Task<TaskExecutionSummary> GetExecutionSummaryAsync(DateTime date)
        {
            var startOfDay = date.Date;
            var endOfDay = startOfDay.AddDays(1);

            var executionResults = await _context.TaskExecutionResults
                .Where(r => r.ExecutionTime >= startOfDay && r.ExecutionTime <= endOfDay)
                .ToListAsync();

            var summary = new TaskExecutionSummary
            {
                Date = date,
                TotalExecutions = executionResults.Count,
                SuccessfulExecutions = executionResults.Count(r => r.Status == Haoliang.Models.System.TaskStatus.Completed),
                FailedExecutions = executionResults.Count(r => r.Status == Haoliang.Models.System.TaskStatus.Failed),
                RunningExecutions = executionResults.Count(r => r.Status == Haoliang.Models.System.TaskStatus.Running),
                ExecutionDetails = executionResults
                    .GroupBy(r => r.TaskId)
                    .ToDictionary(g => g.Key, g => new TaskExecutionDetail
                    {
                        TaskName = g.Key ?? "",
                        TotalExecutions = g.Count(),
                        SuccessfulExecutions = g.Count(r => r.Status == Haoliang.Models.System.TaskStatus.Completed),
                        FailedExecutions = g.Count(r => r.Status == Haoliang.Models.System.TaskStatus.Failed),
                        AverageExecutionTime = g.Average(r => r.ExecutionDurationMs?.TotalMilliseconds ?? 0)
                    })
            };

            return summary;
        }

        public async Task<IEnumerable<TaskExecutionResult>> GetExecutionHistoryAsync(string taskId, int count = 10)
        {
            return await _context.TaskExecutionResults
                .Where(r => r.TaskId == taskId)
                .OrderByDescending(r => r.ExecutionTime)
                .Take(count)
                .ToListAsync();
        }
    }
}