using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Tiku.Application.Assets;
using Tiku.Application.Catalog;
using Tiku.Application.Content;

namespace Tiku.Infrastructure.Content;

public sealed partial class DirectContentService
{
    public Task<SimpleImportResult> PreviewImportAsync(
        DirectContentActor actor,
        SimpleImportCommand command,
        CancellationToken cancellationToken = default)
    {
        return CreateImportJobAsync(actor, command with { DryRun = true }, false, cancellationToken);
    }

    public Task<SimpleImportResult> ExecuteImportAsync(
        DirectContentActor actor,
        SimpleImportCommand command,
        CancellationToken cancellationToken = default)
    {
        return CreateImportJobAsync(actor, command with { DryRun = false }, true, cancellationToken);
    }

    public async Task<ContentImportJobDetail> GetImportJobAsync(
        DirectContentActor actor,
        Guid jobId,
        CancellationToken cancellationToken = default)
    {
        var job = await dbContext.ContentImportJobs.AsNoTracking()
            .Where(item => item.TenantId == actor.TenantId && item.Id == jobId)
            .Select(item => ToJobItem(item))
            .SingleOrDefaultAsync(cancellationToken);
        if (job is null) throw new ContentManagementException("Import job was not found.", "import_job_not_found");

        var items = await dbContext.ContentImportItems.AsNoTracking()
            .Where(item => item.TenantId == actor.TenantId && item.JobId == jobId)
            .OrderBy(item => item.RowNo)
            .Take(MaxLimit)
            .Select(item => ToImportItem(item))
            .ToArrayAsync(cancellationToken);
        var issues = await dbContext.ContentImportIssues.AsNoTracking()
            .Where(issue => issue.TenantId == actor.TenantId && issue.JobId == jobId)
            .OrderBy(issue => issue.RowNo)
            .ThenBy(issue => issue.CreatedAt)
            .Take(MaxLimit)
            .Select(issue => new ContentImportIssueModel(
                issue.Id,
                issue.JobId,
                issue.ItemId,
                issue.RowNo,
                issue.Severity,
                issue.Code,
                issue.FieldPath,
                issue.Message,
                issue.Details))
            .ToArrayAsync(cancellationToken);

        return new ContentImportJobDetail(job, items, issues);
    }

    public async Task<CatalogList<ContentImportIssueModel>> GetImportIssuesAsync(
        DirectContentActor actor,
        Guid jobId,
        CancellationToken cancellationToken = default)
    {
        await AssertImportJobAsync(actor.TenantId, jobId, cancellationToken);
        var issues = await dbContext.ContentImportIssues.AsNoTracking()
            .Where(item => item.TenantId == actor.TenantId && item.JobId == jobId)
            .OrderBy(item => item.RowNo)
            .ThenBy(item => item.CreatedAt)
            .Take(MaxLimit)
            .Select(item => new ContentImportIssueModel(
                item.Id,
                item.JobId,
                item.ItemId,
                item.RowNo,
                item.Severity,
                item.Code,
                item.FieldPath,
                item.Message,
                item.Details))
            .ToArrayAsync(cancellationToken);
        return new CatalogList<ContentImportIssueModel>(issues);
    }

    public async Task<ImportPostCheckResult> RunImportPostCheckAsync(
        DirectContentActor actor,
        Guid jobId,
        CancellationToken cancellationToken = default)
    {
        var job = await dbContext.ContentImportJobs.SingleOrDefaultAsync(
            item => item.TenantId == actor.TenantId && item.Id == jobId,
            cancellationToken);
        if (job is null) throw new ContentManagementException("Import job was not found.", "import_job_not_found");

        var counts = JsonSerializer.SerializeToElement(new
        {
            job.TotalCount,
            job.ValidCount,
            job.ErrorCount,
            job.WarningCount,
            job.InsertedCount,
            job.UpdatedCount,
            job.SkippedCount
        });
        job.Summary = JsonSerializer.SerializeToElement(new
        {
            postCheck = new
            {
                status = job.ErrorCount == 0 ? "passed" : "warning",
                checkedAt = DateTimeOffset.UtcNow,
                counts
            }
        });
        await dbContext.SaveChangesAsync(cancellationToken);
        return new ImportPostCheckResult(job.Id, job.ErrorCount == 0 ? "passed" : "warning", counts, []);
    }

    public async Task<ImportPostCheckResult> GetImportPostCheckAsync(
        DirectContentActor actor,
        Guid jobId,
        CancellationToken cancellationToken = default)
    {
        var job = await dbContext.ContentImportJobs.AsNoTracking().SingleOrDefaultAsync(
            item => item.TenantId == actor.TenantId && item.Id == jobId,
            cancellationToken);
        if (job is null) throw new ContentManagementException("Import job was not found.", "import_job_not_found");

        var issues = await GetImportIssuesAsync(actor, jobId, cancellationToken);
        var counts = JsonSerializer.SerializeToElement(new
        {
            job.TotalCount,
            job.ValidCount,
            job.ErrorCount,
            job.WarningCount,
            job.InsertedCount,
            job.UpdatedCount,
            job.SkippedCount
        });
        return new ImportPostCheckResult(job.Id, job.ErrorCount == 0 ? "passed" : "warning", counts, issues.Items);
    }
}