using MediatR;
using MissionService.Domain.AggregatesModel.MissionAggregate;
using MissionService.Domain.AggregatesModel.TaskAggregate;
using TaskStatus = MissionService.Domain.AggregatesModel.TaskAggregate.TaskStatus;

namespace MissionService.API.Application.Commands;

/// <summary>
/// EN: Handler for StartMissionTaskCommand
/// VI: Handler cho StartMissionTaskCommand
/// </summary>
public class StartMissionTaskCommandHandler : IRequestHandler<StartMissionTaskCommand, StartTaskResult>
{
    private readonly IMissionRepository _missionRepository;
    private readonly IUserTaskRepository _taskRepository;
    private readonly ILogger<StartMissionTaskCommandHandler> _logger;

    public StartMissionTaskCommandHandler(
        IMissionRepository missionRepository,
        IUserTaskRepository taskRepository,
        ILogger<StartMissionTaskCommandHandler> logger)
    {
        _missionRepository = missionRepository;
        _taskRepository = taskRepository;
        _logger = logger;
    }

    public async Task<StartTaskResult> Handle(StartMissionTaskCommand request, CancellationToken cancellationToken)
    {
        // EN: Check if mission exists and is available / VI: Kiểm tra mission tồn tại và khả dụng
        var mission = await _missionRepository.GetByIdAsync(request.MissionId, cancellationToken);
        if (mission == null)
        {
            return new StartTaskResult(false, null, "Mission not found / Không tìm thấy mission");
        }

        if (!mission.IsAvailable())
        {
            return new StartTaskResult(false, null, "Mission not available / Mission không khả dụng");
        }

        // EN: Check if user already has active task for this mission
        // VI: Kiểm tra user đã có task đang hoạt động cho mission này chưa
        var existingTask = await _taskRepository.GetByUserAndMissionAsync(
            request.UserId, request.MissionId, cancellationToken);
        
        if (existingTask != null)
        {
            return new StartTaskResult(false, existingTask.Id, 
                "Task already exists / Task đã tồn tại");
        }

        // EN: Check max completions / VI: Kiểm tra số lần hoàn thành tối đa
        var completions = await _taskRepository.CountCompletionsByUserAndMissionAsync(
            request.UserId, request.MissionId, cancellationToken);
        
        if (completions >= mission.MaxCompletions)
        {
            return new StartTaskResult(false, null, 
                "Max completions reached / Đã đạt số lần hoàn thành tối đa");
        }

        // EN: Create new task / VI: Tạo task mới
        var task = new UserTask(request.UserId, request.MissionId);
        _taskRepository.Add(task);
        await _taskRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "Task {TaskId} started for user {UserId} on mission {MissionId}",
            task.Id, request.UserId, request.MissionId);

        return new StartTaskResult(true, task.Id, "Task started / Đã bắt đầu task");
    }
}

/// <summary>
/// EN: Handler for UpdateTaskProgressCommand
/// VI: Handler cho UpdateTaskProgressCommand
/// </summary>
public class UpdateTaskProgressCommandHandler : IRequestHandler<UpdateTaskProgressCommand, UpdateProgressResult>
{
    private readonly IUserTaskRepository _taskRepository;
    private readonly ILogger<UpdateTaskProgressCommandHandler> _logger;

    public UpdateTaskProgressCommandHandler(
        IUserTaskRepository taskRepository,
        ILogger<UpdateTaskProgressCommandHandler> logger)
    {
        _taskRepository = taskRepository;
        _logger = logger;
    }

    public async Task<UpdateProgressResult> Handle(UpdateTaskProgressCommand request, CancellationToken cancellationToken)
    {
        var task = await _taskRepository.GetByIdAsync(request.TaskId, cancellationToken);
        
        if (task == null)
        {
            return new UpdateProgressResult(false, 0, 0, 0, false, "Task not found / Không tìm thấy task");
        }

        if (task.UserId != request.UserId)
        {
            return new UpdateProgressResult(false, 0, 0, 0, false, "Unauthorized / Không có quyền");
        }

        if (task.Status != TaskStatus.InProgress)
        {
            return new UpdateProgressResult(false, 
                task.Progress.CurrentValue, 
                task.Progress.TargetValue,
                task.Progress.PercentComplete,
                task.Progress.IsComplete,
                "Task not in progress / Task không đang thực hiện");
        }

        try
        {
            task.UpdateProgress(request.CurrentValue);

            // EN: Submit evidence if provided / VI: Nộp bằng chứng nếu có
            if (request.Evidence != null && task.Progress.IsComplete)
            {
                var evidence = MapEvidence(request.Evidence);
                task.SubmitEvidence(evidence);
            }

            // EN: Auto-complete if no verification needed / VI: Tự động hoàn thành nếu không cần xác thực
            if (task.Progress.IsComplete && request.Evidence == null)
            {
                task.AutoComplete();
            }

            _taskRepository.Update(task);
            await _taskRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            return new UpdateProgressResult(
                true,
                task.Progress.CurrentValue,
                task.Progress.TargetValue,
                task.Progress.PercentComplete,
                task.Progress.IsComplete,
                task.Progress.IsComplete ? "Task completed / Hoàn thành task" : "Progress updated / Đã cập nhật tiến độ");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update task {TaskId}", request.TaskId);
            return new UpdateProgressResult(false, 0, 0, 0, false, "Update failed / Cập nhật thất bại");
        }
    }

    private static TaskEvidence MapEvidence(TaskEvidenceDto dto)
    {
        return dto.Type.ToLowerInvariant() switch
        {
            "watchduration" => TaskEvidence.WatchDuration(int.Parse(dto.Data)),
            "click" => TaskEvidence.Click(dto.Data),
            "socialproof" => TaskEvidence.SocialProof(dto.ScreenshotUrl ?? "", dto.Data),
            "invitecode" => TaskEvidence.InviteCode(dto.Data),
            _ => TaskEvidence.Upload(dto.Data, dto.ScreenshotUrl != null)
        };
    }
}

/// <summary>
/// EN: Handler for ClaimTaskRewardCommand
/// VI: Handler cho ClaimTaskRewardCommand
/// </summary>
public class ClaimTaskRewardCommandHandler : IRequestHandler<ClaimTaskRewardCommand, ClaimRewardResult>
{
    private readonly IUserTaskRepository _taskRepository;
    private readonly IMissionRepository _missionRepository;
    private readonly ILogger<ClaimTaskRewardCommandHandler> _logger;

    public ClaimTaskRewardCommandHandler(
        IUserTaskRepository taskRepository,
        IMissionRepository missionRepository,
        ILogger<ClaimTaskRewardCommandHandler> logger)
    {
        _taskRepository = taskRepository;
        _missionRepository = missionRepository;
        _logger = logger;
    }

    public async Task<ClaimRewardResult> Handle(ClaimTaskRewardCommand request, CancellationToken cancellationToken)
    {
        var task = await _taskRepository.GetByIdAsync(request.TaskId, cancellationToken);
        
        if (task == null)
        {
            return new ClaimRewardResult(false, null, "Task not found / Không tìm thấy task");
        }

        if (task.UserId != request.UserId)
        {
            return new ClaimRewardResult(false, null, "Unauthorized / Không có quyền");
        }

        if (task.Status != TaskStatus.Completed)
        {
            return new ClaimRewardResult(false, null, "Task not completed / Task chưa hoàn thành");
        }

        if (task.RewardClaimed)
        {
            return new ClaimRewardResult(false, null, "Reward already claimed / Đã nhận thưởng rồi");
        }

        try
        {
            var mission = await _missionRepository.GetByIdAsync(task.MissionId, cancellationToken);
            var points = mission?.Reward.Points ?? 0;

            task.ClaimReward();
            _taskRepository.Update(task);
            await _taskRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

            _logger.LogInformation(
                "Reward claimed for task {TaskId} by user {UserId}, points: {Points}",
                request.TaskId, request.UserId, points);

            return new ClaimRewardResult(true, points, "Reward claimed / Đã nhận thưởng");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to claim reward for task {TaskId}", request.TaskId);
            return new ClaimRewardResult(false, null, "Claim failed / Nhận thưởng thất bại");
        }
    }
}
