using Microsoft.EntityFrameworkCore;
using Tiku.Application.Catalog;
using Tiku.Application.Content;
using Tiku.Domain.Catalog;
using Tiku.Domain.Content;
using Tiku.Domain.QuestionBanks;

namespace Tiku.Infrastructure.Content;

public sealed partial class DirectContentService
{
    public async Task<CatalogList<VideoManagementItem>> GetVideosAsync(
        DirectContentActor actor,
        AdminLimitFilter filter,
        CancellationToken cancellationToken = default)
    {
        var query = dbContext.VideoExplanations.AsNoTracking().Where(item => item.TenantId == actor.TenantId);
        if (filter.SubjectId.HasValue) query = query.Where(item => item.SubjectId == filter.SubjectId.Value);

        if (!string.Equals(filter.Status, "all", StringComparison.OrdinalIgnoreCase))
            query = query.Where(item => item.IsActive);

        if (!string.IsNullOrWhiteSpace(filter.Keyword))
        {
            var keyword = filter.Keyword.Trim();
            query = query.Where(item =>
                item.Title.Contains(keyword) || (item.Description != null && item.Description.Contains(keyword)));
        }

        var items = await query
            .OrderBy(item => item.SortOrder)
            .ThenByDescending(item => item.CreatedAt)
            .Take(ResolveLimit(filter.Limit))
            .Select(item => ToVideoItem(item))
            .ToArrayAsync(cancellationToken);
        return new CatalogList<VideoManagementItem>(items);
    }

    public async Task<ContentManagementResult<VideoManagementItem>> UpsertVideoAsync(
        DirectContentActor actor,
        VideoExplanationCommand command,
        CancellationToken cancellationToken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(command.Title);
        await AssertReferenceAsync<Subject>(actor.TenantId, command.SubjectId, "subject_not_found", cancellationToken);
        var item = await ResolveByIdOrLegacyAsync(dbContext.VideoExplanations, actor.TenantId, command.Id,
            command.LegacyId, cancellationToken);
        var isNew = item is null;
        item ??= new VideoExplanation { Id = command.Id ?? Guid.NewGuid(), TenantId = actor.TenantId };
        item.SubjectId = command.SubjectId;
        item.LegacyId = Normalize(command.LegacyId);
        item.Title = command.Title.Trim();
        item.Description = Normalize(command.Description);
        item.VideoUrl = Normalize(command.VideoUrl);
        item.ThumbnailUrl = Normalize(command.ThumbnailUrl);
        item.DurationSeconds = command.DurationSeconds;
        item.KnowledgeTags = JsonArrayOrDefault(command.KnowledgeTags);
        item.IsGeneral = command.IsGeneral ?? item.IsGeneral;
        item.Difficulty = command.Difficulty;
        item.SortOrder = command.Order ?? item.SortOrder;
        item.IsActive = command.IsActive ?? item.IsActive;
        item.Metadata = JsonObjectOrDefault(command.Metadata);
        if (isNew) dbContext.VideoExplanations.Add(item);

        await dbContext.SaveChangesAsync(cancellationToken);
        return new ContentManagementResult<VideoManagementItem>(ToVideoItem(item));
    }

    public async Task<ContentManagementResult<QuestionVideoManagementItem>> BindQuestionVideoAsync(
        DirectContentActor actor,
        QuestionVideoCommand command,
        CancellationToken cancellationToken = default)
    {
        await AssertReferenceAsync<Question>(actor.TenantId, command.QuestionId, "question_not_found",
            cancellationToken);
        await AssertReferenceAsync<VideoExplanation>(actor.TenantId, command.VideoId, "video_not_found",
            cancellationToken);
        var item = await dbContext.QuestionVideos.SingleOrDefaultAsync(
            link => link.TenantId == actor.TenantId && link.QuestionId == command.QuestionId &&
                    link.VideoId == command.VideoId,
            cancellationToken);
        var isNew = item is null;
        item ??= new QuestionVideo { TenantId = actor.TenantId };
        item.QuestionId = command.QuestionId;
        item.VideoId = command.VideoId;
        item.LegacyId = Normalize(command.LegacyId);
        item.VideoType = Parse(command.VideoType, QuestionVideoType.Specific, "question_video_type_invalid");
        item.SortOrder = command.Order ?? item.SortOrder;
        item.Metadata = JsonObjectOrDefault(command.Metadata);
        if (isNew) dbContext.QuestionVideos.Add(item);

        var question = await dbContext.Questions.SingleAsync(
            question => question.TenantId == actor.TenantId && question.Id == command.QuestionId,
            cancellationToken);
        question.HasVideoExplanation = true;
        await dbContext.SaveChangesAsync(cancellationToken);
        return new ContentManagementResult<QuestionVideoManagementItem>(ToQuestionVideoItem(item));
    }
}