using Microsoft.EntityFrameworkCore;
using WorkClub.Application.Interfaces;
using WorkClub.Application.Tasks.DTOs;
using WorkClub.Domain.Entities;
using WorkClub.Domain.Enums;
using WorkClub.Infrastructure.Data;

namespace WorkClub.Api.Services;

public class TaskService
{
    private readonly AppDbContext _context;
    private readonly ITenantProvider _tenantProvider;

    public TaskService(AppDbContext context, ITenantProvider tenantProvider)
    {
        _context = context;
        _tenantProvider = tenantProvider;
    }

    public async Task<TaskListDto> GetTasksAsync(string? statusFilter, int page, int pageSize)
    {
        var query = _context.WorkItems.AsQueryable();

        if (!string.IsNullOrEmpty(statusFilter))
        {
            if (Enum.TryParse<WorkItemStatus>(statusFilter, ignoreCase: true, out var status))
            {
                query = query.Where(w => w.Status == status);
            }
        }

        var total = await query.CountAsync();

        var items = await query
            .OrderBy(w => w.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var itemDtos = items.Select(w => new TaskListItemDto(
            w.Id,
            w.Title,
            w.Status.ToString(),
            w.AssigneeId,
            w.CreatedAt
        )).ToList();

        return new TaskListDto(itemDtos, total, page, pageSize);
    }

    public async Task<TaskDetailDto?> GetTaskByIdAsync(Guid id)
    {
        var workItem = await _context.WorkItems.FindAsync(id);

        if (workItem == null)
            return null;

        return new TaskDetailDto(
            workItem.Id,
            workItem.Title,
            workItem.Description,
            workItem.Status.ToString(),
            workItem.AssigneeId,
            workItem.CreatedById,
            workItem.ClubId,
            workItem.DueDate,
            workItem.CreatedAt,
            workItem.UpdatedAt
        );
    }

    public async Task<(TaskDetailDto? task, string? error)> CreateTaskAsync(CreateTaskRequest request, Guid createdById)
    {
        var tenantId = _tenantProvider.GetTenantId();

        var workItem = new WorkItem
        {
            Id = Guid.NewGuid(),
            TenantId = tenantId,
            Title = request.Title,
            Description = request.Description,
            Status = WorkItemStatus.Open,
            ClubId = request.ClubId,
            AssigneeId = request.AssigneeId,
            DueDate = request.DueDate,
            CreatedById = createdById,
            CreatedAt = DateTimeOffset.UtcNow,
            UpdatedAt = DateTimeOffset.UtcNow
        };

        _context.WorkItems.Add(workItem);
        await _context.SaveChangesAsync();

        var dto = new TaskDetailDto(
            workItem.Id,
            workItem.Title,
            workItem.Description,
            workItem.Status.ToString(),
            workItem.AssigneeId,
            workItem.CreatedById,
            workItem.ClubId,
            workItem.DueDate,
            workItem.CreatedAt,
            workItem.UpdatedAt
        );

        return (dto, null);
    }

    public async Task<(TaskDetailDto? task, string? error, bool isConflict)> UpdateTaskAsync(Guid id, UpdateTaskRequest request)
    {
        var workItem = await _context.WorkItems.FindAsync(id);

        if (workItem == null)
            return (null, "Task not found", false);

        if (request.Title != null)
            workItem.Title = request.Title;

        if (request.Description != null)
            workItem.Description = request.Description;

        if (request.AssigneeId.HasValue)
            workItem.AssigneeId = request.AssigneeId;

        if (request.DueDate.HasValue)
            workItem.DueDate = request.DueDate;

        if (request.Status != null)
        {
            if (!Enum.TryParse<WorkItemStatus>(request.Status, ignoreCase: true, out var newStatus))
            {
                return (null, $"Invalid status: {request.Status}", false);
            }

            if (!workItem.CanTransitionTo(newStatus))
            {
                return (null, $"Cannot transition from {workItem.Status} to {newStatus}", false);
            }

            workItem.TransitionTo(newStatus);
        }

        workItem.UpdatedAt = DateTimeOffset.UtcNow;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            return (null, "Task was modified by another user. Please refresh and try again.", true);
        }

        var dto = new TaskDetailDto(
            workItem.Id,
            workItem.Title,
            workItem.Description,
            workItem.Status.ToString(),
            workItem.AssigneeId,
            workItem.CreatedById,
            workItem.ClubId,
            workItem.DueDate,
            workItem.CreatedAt,
            workItem.UpdatedAt
        );

        return (dto, null, false);
    }

    public async Task<bool> DeleteTaskAsync(Guid id)
    {
        var workItem = await _context.WorkItems.FindAsync(id);

        if (workItem == null)
            return false;

        _context.WorkItems.Remove(workItem);
        await _context.SaveChangesAsync();

        return true;
    }
}
