using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using ColaFlow.Modules.IssueManagement.Application.DTOs;
using ColaFlow.Modules.IssueManagement.Application.Commands.CreateIssue;
using ColaFlow.Modules.IssueManagement.Application.Commands.UpdateIssue;
using ColaFlow.Modules.IssueManagement.Application.Commands.ChangeIssueStatus;
using ColaFlow.Modules.IssueManagement.Application.Commands.AssignIssue;
using ColaFlow.Modules.IssueManagement.Application.Commands.DeleteIssue;
using ColaFlow.Modules.IssueManagement.Application.Queries.GetIssueById;
using ColaFlow.Modules.IssueManagement.Application.Queries.ListIssues;
using ColaFlow.Modules.IssueManagement.Application.Queries.ListIssuesByStatus;
using ColaFlow.Modules.IssueManagement.Domain.Enums;
using ColaFlow.API.Services;
using System.Security.Claims;

namespace ColaFlow.API.Controllers;

[ApiController]
[Route("api/v1/projects/{projectId:guid}/issues")]
[Authorize]
public class IssuesController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly IRealtimeNotificationService _notificationService;

    public IssuesController(IMediator mediator, IRealtimeNotificationService notificationService)
    {
        _mediator = mediator;
        _notificationService = notificationService;
    }

    [HttpGet]
    public async Task<IActionResult> ListIssues(Guid projectId, [FromQuery] IssueStatus? status = null, CancellationToken cancellationToken = default)
    {
        var result = status.HasValue
            ? await _mediator.Send(new ListIssuesByStatusQuery(projectId, status.Value), cancellationToken)
            : await _mediator.Send(new ListIssuesQuery(projectId), cancellationToken);
        return Ok(result);
    }

    [HttpGet("{id:guid}")]
    public async Task<IActionResult> GetIssue(Guid projectId, Guid id, CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetIssueByIdQuery(id), cancellationToken);
        if (result == null)
            return NotFound();
        return Ok(result);
    }

    [HttpPost]
    public async Task<IActionResult> CreateIssue(Guid projectId, [FromBody] CreateIssueRequest request, CancellationToken cancellationToken = default)
    {
        var tenantId = GetTenantId();
        var userId = GetUserId();
        var command = new CreateIssueCommand(projectId, tenantId, request.Title, request.Description, request.Type, request.Priority, userId);
        var result = await _mediator.Send(command, cancellationToken);
        await _notificationService.NotifyIssueCreated(tenantId, projectId, result);
        return CreatedAtAction(nameof(GetIssue), new { projectId, id = result.Id }, result);
    }

    [HttpPut("{id:guid}")]
    public async Task<IActionResult> UpdateIssue(Guid projectId, Guid id, [FromBody] UpdateIssueRequest request, CancellationToken cancellationToken = default)
    {
        var command = new UpdateIssueCommand(id, request.Title, request.Description, request.Priority);
        await _mediator.Send(command, cancellationToken);
        var issue = await _mediator.Send(new GetIssueByIdQuery(id), cancellationToken);
        if (issue != null)
            await _notificationService.NotifyIssueUpdated(issue.TenantId, projectId, issue);
        return NoContent();
    }

    [HttpPut("{id:guid}/status")]
    public async Task<IActionResult> ChangeStatus(Guid projectId, Guid id, [FromBody] ChangeStatusRequest request, CancellationToken cancellationToken = default)
    {
        var command = new ChangeIssueStatusCommand(id, request.Status);
        await _mediator.Send(command, cancellationToken);
        var issue = await _mediator.Send(new GetIssueByIdQuery(id), cancellationToken);
        if (issue != null)
            await _notificationService.NotifyIssueStatusChanged(issue.TenantId, projectId, id, request.OldStatus?.ToString() ?? "Unknown", request.Status.ToString());
        return NoContent();
    }

    [HttpPut("{id:guid}/assign")]
    public async Task<IActionResult> AssignIssue(Guid projectId, Guid id, [FromBody] AssignIssueRequest request, CancellationToken cancellationToken = default)
    {
        var command = new AssignIssueCommand(id, request.AssigneeId);
        await _mediator.Send(command, cancellationToken);
        var issue = await _mediator.Send(new GetIssueByIdQuery(id), cancellationToken);
        if (issue != null)
            await _notificationService.NotifyIssueUpdated(issue.TenantId, projectId, issue);
        return NoContent();
    }

    [HttpDelete("{id:guid}")]
    public async Task<IActionResult> DeleteIssue(Guid projectId, Guid id, CancellationToken cancellationToken = default)
    {
        var issue = await _mediator.Send(new GetIssueByIdQuery(id), cancellationToken);
        await _mediator.Send(new DeleteIssueCommand(id), cancellationToken);
        if (issue != null)
            await _notificationService.NotifyIssueDeleted(issue.TenantId, projectId, id);
        return NoContent();
    }

    private Guid GetTenantId()
    {
        var claim = User.FindFirst("tenant_id");
        if (claim == null || !Guid.TryParse(claim.Value, out var id))
            throw new UnauthorizedAccessException("TenantId not found");
        return id;
    }

    private Guid GetUserId()
    {
        var claim = User.FindFirst(ClaimTypes.NameIdentifier);
        if (claim == null || !Guid.TryParse(claim.Value, out var id))
            throw new UnauthorizedAccessException("UserId not found");
        return id;
    }
}

public record CreateIssueRequest
{
    public string Title { get; init; } = string.Empty;
    public string Description { get; init; } = string.Empty;
    public IssueType Type { get; init; } = IssueType.Task;
    public IssuePriority Priority { get; init; } = IssuePriority.Medium;
}

public record UpdateIssueRequest
{
    public string Title { get; init; } = string.Empty;
    public string Description { get; init; } = string.Empty;
    public IssuePriority Priority { get; init; } = IssuePriority.Medium;
}

public record ChangeStatusRequest
{
    public IssueStatus Status { get; init; }
    public IssueStatus? OldStatus { get; init; }
}

public record AssignIssueRequest
{
    public Guid? AssigneeId { get; init; }
}
