using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Tiku.Application.PlatformAdmin;
using Tiku.Application.Security;
using Tiku.Domain.Operations;
using Tiku.Domain.Tenancy;

namespace Tiku.Infrastructure.PlatformAdmin;

internal sealed partial class PlatformAdminService
{
    public async Task<PlatformDomainList> GetDomainsAsync(
        PlatformAdminActor actor,
        PlatformAdminQuery query,
        CancellationToken cancellationToken = default)
    {
        await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformTenantManage, cancellationToken);
        return await ExecuteSystemAsync("platform domain list", async dbContext =>
        {
            var domains = dbContext.TenantDomains.AsNoTracking();
            if (!string.IsNullOrWhiteSpace(query.Status))
                domains = domains.Where(domain => domain.Status == ParseDomainStatus(query.Status));

            if (!string.IsNullOrWhiteSpace(query.Search))
            {
                var search = query.Search.Trim();
                domains = domains.Where(domain => domain.Host.Contains(search));
            }

            return new PlatformDomainList(await domains
                .OrderByDescending(domain => domain.UpdatedAt)
                .Take(Limit(query.Limit))
                .Select(domain => ToDomainItem(domain))
                .ToArrayAsync(cancellationToken));
        }, cancellationToken);
    }

    public async Task<PlatformDomainRecheckResult> RecheckDomainAsync(
        PlatformAdminActor actor,
        Guid domainId,
        CancellationToken cancellationToken = default)
    {
        await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformTenantManage, cancellationToken);
        return await ExecuteSystemAsync("platform domain recheck", async dbContext =>
        {
            var domain =
                await dbContext.TenantDomains.SingleOrDefaultAsync(domain => domain.Id == domainId, cancellationToken)
                ?? throw new PlatformAdminException("Tenant domain was not found.", "domain_not_found");
            domain.Status = domain.Status == TenantDomainStatus.Disabled
                ? TenantDomainStatus.Disabled
                : TenantDomainStatus.Pending;
            domain.LastCheckedAt = DateTimeOffset.UtcNow;
            domain.LastFailureReason = null;
            dbContext.BackgroundJobs.Add(new BackgroundJob
            {
                TenantId = domain.TenantId,
                JobType = "tenant_domain_recheck",
                Payload = JsonSerializer.SerializeToElement(new { domain.Id, domain.Host }),
                MaxRetries = 3
            });
            AddAudit(dbContext, actor, "platform.tenant_domain.recheck_requested", domain.TenantId,
                new { domain.Id, domain.Host });
            await dbContext.SaveChangesAsync(cancellationToken);
            return new PlatformDomainRecheckResult(domain.Id, domain.Status, domain.LastCheckedAt.Value);
        }, cancellationToken);
    }
}