using Nexus.Api.Models;

namespace Nexus.Api.Services;

public sealed class DashboardService(
    IOpenClawGatewayClient gateway,
    ITaskService taskService,
    ILogger<DashboardService> logger) : IDashboardService
{
    public async Task<DashboardStatus> GetStatusAsync()
    {
        try
        {
            return await gateway.GetStatusAsync();
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard status check failed");
            return new DashboardStatus(false, "Offline", 0, 0);
        }
    }

    public async Task<List<DashboardAgentInfo>> GetAgentsAsync()
    {
        try
        {
            return await gateway.GetAgentsAsync();
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard agents fetch failed");
            return [];
        }
    }

    public async Task<List<FeedEntry>> GetOperationsAsync(int limit, string? agentFilter)
    {
        try
        {
            var entries = await gateway.GetAllAgentOperationsAsync(Math.Clamp(limit, 1, 100));

            if (!string.IsNullOrWhiteSpace(agentFilter))
            {
                entries = entries
                    .Where(e => string.Equals(e.AgentId, agentFilter, StringComparison.OrdinalIgnoreCase)
                             || string.Equals(e.Agent, agentFilter, StringComparison.OrdinalIgnoreCase))
                    .ToList();
            }

            return entries;
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard operations fetch failed");
            return [];
        }
    }

    public async Task<ChatResponse> SendChatAsync(string agentId, string message)
    {
        try
        {
            return await gateway.SendChatMessageAsync(agentId, message);
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard chat send failed");
            return new ChatResponse(false, null, "Gateway nicht erreichbar");
        }
    }

    public async Task<List<MessageEntry>> GetMessagesAsync(string? sessionKey, int limit, int offset)
    {
        try
        {
            var key = string.IsNullOrWhiteSpace(sessionKey) ? "agent:iris:main" : sessionKey.Trim();
            var messages = await gateway.GetSessionHistoryAsync(key, Math.Clamp(limit, 1, 200), Math.Max(0, offset));
            return messages
                .Where(m => string.Equals(m.Role, "user", StringComparison.OrdinalIgnoreCase)
                         || string.Equals(m.Role, "assistant", StringComparison.OrdinalIgnoreCase))
                .ToList();
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard messages fetch failed");
            return [];
        }
    }

    public async Task<List<QueueItem>> GetQueueAsync(CancellationToken ct)
    {
        try
        {
            var cronTask = gateway.GetQueueAsync();
            var tasksTask = taskService.GetOpenAsync(ct);
            await Task.WhenAll(cronTask, tasksTask);

            var merged = new List<QueueItem>(cronTask.Result);
            foreach (var t in tasksTask.Result)
            {
                merged.Add(new QueueItem("task-" + t.Id, t.Title, t.State, NormalizePriority(t.Priority), "task", "--"));
            }

            return merged
                .OrderBy(q => PriorityOrder.GetValueOrDefault(q.Priority, 99))
                .ToList();
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "Dashboard queue fetch failed");
            return [];
        }
    }

    public async Task<QueueDeleteResult> DeleteQueueItemAsync(string id, string? source, CancellationToken ct)
    {
        if (string.Equals(source, "cron", StringComparison.OrdinalIgnoreCase))
        {
            var ok = await gateway.DeleteCronJobAsync(id);
            return new QueueDeleteResult(ok ? QueueDeleteOutcome.Deleted : QueueDeleteOutcome.GatewayError);
        }

        if (string.Equals(source, "task", StringComparison.OrdinalIgnoreCase) || id.StartsWith("task-"))
        {
            if (!id.StartsWith("task-")) return new QueueDeleteResult(QueueDeleteOutcome.InvalidTaskId);
            if (!Guid.TryParse(id["task-".Length..], out var guid))
                return new QueueDeleteResult(QueueDeleteOutcome.InvalidTaskId);

            var result = await taskService.CompleteViaQueueAsync(guid, ct);
            return result.Outcome switch
            {
                TaskOperationOutcome.NotFound => new QueueDeleteResult(QueueDeleteOutcome.TaskNotFound),
                _ => new QueueDeleteResult(QueueDeleteOutcome.Deleted)
            };
        }

        var deleted = await gateway.DeleteCronJobAsync(id);
        return new QueueDeleteResult(deleted ? QueueDeleteOutcome.Deleted : QueueDeleteOutcome.NotFound);
    }

    public async Task<QueuePriorityResult> CycleQueuePriorityAsync(string id, CancellationToken ct)
    {
        if (!id.StartsWith("task-"))
            return new QueuePriorityResult(QueuePriorityOutcome.Ignored);

        if (!Guid.TryParse(id["task-".Length..], out var guid))
            return new QueuePriorityResult(QueuePriorityOutcome.InvalidTaskId);

        var result = await taskService.CyclePriorityAsync(guid, ct);
        return result.Outcome switch
        {
            TaskOperationOutcome.NotFound => new QueuePriorityResult(QueuePriorityOutcome.TaskNotFound),
            _ => new QueuePriorityResult(QueuePriorityOutcome.Updated, result.Task?.Priority)
        };
    }

    public async Task<AgentModelInfo?> GetAgentModelAsync(string agentId)
    {
        try
        {
            return await gateway.GetAgentModelAsync(agentId);
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "GetAgentModel failed for {AgentId}", agentId);
            return null;
        }
    }

    public async Task<bool> SetAgentModelAsync(string agentId, string model)
    {
        try
        {
            return await gateway.SetAgentModelAsync(agentId, model);
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "SetAgentModel failed for {AgentId}", agentId);
            return false;
        }
    }

    public async Task<List<AgentActivityEntry>> GetAgentActivityAsync(string agentId, int limit)
    {
        try
        {
            return await gateway.GetAgentActivityAsync(agentId, Math.Clamp(limit, 1, 20));
        }
        catch (Exception ex)
        {
            logger.LogWarning(ex, "GetAgentActivity failed for {AgentId}", agentId);
            return [];
        }
    }

    public List<ModelOption> GetAvailableModels() => gateway.GetAvailableModels();

    private static string NormalizePriority(string priority) => priority.ToLowerInvariant() switch
    {
        "high" or "critical" or "urgent" => "high",
        "low" or "minor" => "low",
        _ => "medium"
    };

    private static readonly Dictionary<string, int> PriorityOrder = new(StringComparer.OrdinalIgnoreCase)
    {
        ["high"] = 0, ["medium"] = 1, ["low"] = 2
    };
}
