using System.Text.Json;
using Tiku.Domain.Operations;

namespace Tiku.Application.Jobs;

public sealed class BackgroundJobException(string code, string message) : Exception(message)
{
    public string Code { get; } = code;
}

public sealed record CreateBackgroundJobCommand(
    Guid TenantId,
    string JobType,
    JsonElement Payload,
    DateTimeOffset? RunAfter = null,
    int MaxRetries = 3,
    string? IdempotencyKey = null,
    bool IsSystemJob = false);

public sealed record BackgroundJobItem(
    Guid Id,
    Guid TenantId,
    string JobType,
    string? IdempotencyKey,
    BackgroundJobStatus Status,
    int RetryCount,
    int MaxRetries,
    DateTimeOffset? RunAfter,
    DateTimeOffset? StartedAt,
    DateTimeOffset? CompletedAt,
    DateTimeOffset? CancellationRequestedAt,
    Guid? CancellationRequestedBy,
    string? CancellationReason,
    string? LastError,
    Guid? OutputAssetId,
    JsonElement Result);

public interface IBackgroundJobQueue
{
    Task<BackgroundJobItem> EnqueueAsync(
        CreateBackgroundJobCommand command,
        CancellationToken cancellationToken = default);
}

public interface IBackgroundJobProcessor
{
    Task<int> ProcessPendingAsync(
        string workerId,
        int batchSize,
        bool includeImmediateJobs = true,
        CancellationToken cancellationToken = default);

    Task<bool> ProcessRequestedAsync(
        Guid jobId,
        Guid tenantId,
        string jobType,
        string workerId,
        CancellationToken cancellationToken = default);
}

public interface IBackgroundJobOperations
{
    Task<IReadOnlyCollection<BackgroundJobItem>> ListAsync(
        Guid tenantId,
        string? jobType = null,
        int limit = 50,
        CancellationToken cancellationToken = default);

    Task<BackgroundJobItem?> GetAsync(
        Guid jobId,
        Guid? tenantId,
        CancellationToken cancellationToken = default);

    Task<IReadOnlyCollection<BackgroundJobItem>> ListPlatformAsync(
        Guid? tenantId = null,
        string? jobType = null,
        BackgroundJobStatus? status = null,
        int limit = 100,
        CancellationToken cancellationToken = default);

    Task<BackgroundJobItem> RequestCancellationAsync(
        Guid jobId,
        Guid? tenantId,
        Guid actorUserId,
        string reason,
        CancellationToken cancellationToken = default);

    Task<BackgroundJobItem> RetryAsync(
        Guid jobId,
        Guid? tenantId,
        Guid actorUserId,
        CancellationToken cancellationToken = default);
}

public interface IBackgroundJobService :
    IBackgroundJobQueue,
    IBackgroundJobProcessor,
    IBackgroundJobOperations;

public sealed record BackgroundJobExecutionContext(
    Guid JobId,
    Guid TenantId,
    string JobType,
    JsonElement Payload);

public sealed record BackgroundJobHandlerResult(
    JsonElement Result,
    Guid? OutputAssetId = null);

public sealed class BackgroundJobHandlerException(string code, string message, Exception? innerException = null)
    : Exception(message, innerException)
{
    public string Code { get; } = code;
}

public interface IBackgroundJobHandler
{
    string JobType { get; }

    Task<BackgroundJobHandlerResult> HandleAsync(
        BackgroundJobExecutionContext context,
        CancellationToken cancellationToken = default);

    Task HandleFailureAsync(
        BackgroundJobExecutionContext context,
        Exception exception,
        CancellationToken cancellationToken = default)
    {
        return Task.CompletedTask;
    }
}
