using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Tiku.Application.Content;
using Tiku.Application.QuestionBanks;
using Tiku.Domain.Common;
using Tiku.Domain.Content;

namespace Tiku.Api.Contracts;

public sealed class ContentManagementQueryDto
{
    public Guid? RegionId { get; set; }

    public Guid? EntryId { get; set; }

    public Guid? NodeId { get; set; }

    public Guid? CollectionId { get; set; }

    [StringLength(64)]
    [RegularExpression("^(root|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$")]
    public string? ParentId { get; set; }

    [StringLength(50)]
    public string? EntryType { get; set; }

    [StringLength(50)]
    public string? CollectionType { get; set; }

    [StringLength(50)]
    public string? Mode { get; set; }

    [StringLength(50)]
    public string? MarkerType { get; set; }

    [StringLength(100)]
    public string? Keyword { get; set; }

    public bool IncludeInactive { get; set; }

    [Range(1, 1000)]
    public int? Limit { get; set; }

    public ContentManagementFilter ToFilter()
    {
        return new ContentManagementFilter(
            RegionId,
            EntryId,
            NodeId,
            CollectionId,
            ParentId,
            EntryType,
            CollectionType,
            Mode,
            MarkerType,
            Keyword,
            IncludeInactive,
            Limit);
    }
}

public sealed class UpsertContentEntryDto
{
    public Guid? Id { get; set; }

    public Guid? RegionId { get; set; }

    [StringLength(64)]
    public string? LegacyId { get; set; }

    [StringLength(100)]
    public string? EntryKey { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; } = string.Empty;

    [StringLength(50)]
    public string? EntryType { get; set; }

    [StringLength(100)]
    public string? Icon { get; set; }

    [StringLength(500)]
    public string? Route { get; set; }

    [StringLength(2000)]
    public string? Description { get; set; }

    [StringLength(50)]
    public string? Visibility { get; set; }

    public JsonElement AccessRules { get; set; } = JsonDefaults.Object();

    public JsonElement LayoutConfig { get; set; } = JsonDefaults.Object();

    public int? Order { get; set; }

    public bool? IsActive { get; set; }

    public UpsertContentEntryCommand ToCommand()
    {
        return new UpsertContentEntryCommand(
            Id,
            RegionId,
            LegacyId,
            EntryKey,
            Name,
            EntryType,
            Icon,
            Route,
            Description,
            Visibility,
            AccessRules,
            LayoutConfig,
            Order,
            IsActive);
    }
}

public sealed class UpsertContentNodeDto
{
    public Guid? Id { get; set; }

    [Required]
    public Guid EntryId { get; set; }

    public Guid? RegionId { get; set; }

    public Guid? ParentId { get; set; }

    [StringLength(64)]
    public string? LegacyId { get; set; }

    [StringLength(100)]
    public string? NodeKey { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; } = string.Empty;

    [StringLength(50)]
    public string? NodeType { get; set; }

    [StringLength(50)]
    public string? MarkerType { get; set; }

    public JsonElement MarkerConfig { get; set; } = JsonDefaults.Object();

    public int? Order { get; set; }

    public bool? IsActive { get; set; }

    public bool? IsSelectable { get; set; }

    public bool? IsLeaf { get; set; }

    public JsonElement AccessRules { get; set; } = JsonDefaults.Object();

    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public UpsertContentNodeCommand ToCommand()
    {
        return new UpsertContentNodeCommand(
            Id,
            EntryId,
            RegionId,
            ParentId,
            LegacyId,
            NodeKey,
            Name,
            NodeType,
            MarkerType,
            MarkerConfig,
            Order,
            IsActive,
            IsSelectable,
            IsLeaf,
            AccessRules,
            Metadata);
    }
}

public sealed class UpsertQuestionCollectionDto
{
    public Guid? Id { get; set; }

    public Guid? RegionId { get; set; }

    public Guid? EntryId { get; set; }

    public Guid? NodeId { get; set; }

    public Guid? SubjectId { get; set; }

    public Guid? CategoryId { get; set; }

    public Guid? QuestionBankId { get; set; }

    [StringLength(64)]
    public string? LegacyId { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; } = string.Empty;

    [StringLength(50)]
    public string? CollectionType { get; set; }

    [StringLength(50)]
    public string? SourceType { get; set; }

    public JsonElement Filters { get; set; } = JsonDefaults.Object();

    public decimal? TotalScore { get; set; }

    public int? DurationMinutes { get; set; }

    [StringLength(50)]
    public string? Status { get; set; }

    public int? Order { get; set; }

    public JsonElement AccessRules { get; set; } = JsonDefaults.Object();

    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public UpsertQuestionCollectionCommand ToCommand()
    {
        return new UpsertQuestionCollectionCommand(
            Id,
            RegionId,
            EntryId,
            NodeId,
            SubjectId,
            CategoryId,
            QuestionBankId,
            LegacyId,
            Name,
            CollectionType,
            SourceType,
            Filters,
            TotalScore,
            DurationMinutes,
            Status,
            Order,
            AccessRules,
            Metadata);
    }
}

public sealed class CollectionQuestionDto
{
    [Required]
    public Guid QuestionId { get; set; }

    [Required]
    public QuestionSource Source { get; set; } = QuestionSource.Tenant;

    [StringLength(100)]
    public string? SectionKey { get; set; }

    public int? Order { get; set; }

    public decimal? Score { get; set; }

    public bool? Required { get; set; }

    public JsonElement Metadata { get; set; } = JsonDefaults.Object();

    public CollectionQuestionCommand ToCommand()
    {
        return new CollectionQuestionCommand(
            new QuestionLocator(Source, QuestionId),
            SectionKey,
            Order,
            Score,
            Required,
            Metadata);
    }
}

public sealed class ReplaceCollectionItemsDto
{
    [Required]
    public Guid CollectionId { get; set; }

    public IReadOnlyCollection<CollectionQuestionDto> Questions { get; set; } = [];

    public ReplaceCollectionItemsCommand ToCommand()
    {
        return new ReplaceCollectionItemsCommand(
            CollectionId,
            Questions.Select(question => question.ToCommand()).ToArray());
    }
}

public sealed class UpsertPracticeBlueprintDto
{
    public Guid? Id { get; set; }

    public Guid? RegionId { get; set; }

    public Guid? EntryId { get; set; }

    public Guid? NodeId { get; set; }

    public Guid? CollectionId { get; set; }

    [StringLength(64)]
    public string? LegacyId { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; } = string.Empty;

    [StringLength(50)]
    public string? Mode { get; set; }

    [StringLength(50)]
    public string? AssemblyType { get; set; }

    public int? QuestionLimit { get; set; }

    public int? DurationMinutes { get; set; }

    public decimal? TotalScore { get; set; }

    public decimal? PassScore { get; set; }

    public JsonElement Sections { get; set; } = JsonDefaults.Array();

    public JsonElement Rules { get; set; } = JsonDefaults.Object();

    public JsonElement AccessRules { get; set; } = JsonDefaults.Object();

    [StringLength(50)]
    public string? Status { get; set; }

    public int? Order { get; set; }

    public UpsertPracticeBlueprintCommand ToCommand()
    {
        return new UpsertPracticeBlueprintCommand(
            Id,
            RegionId,
            EntryId,
            NodeId,
            CollectionId,
            LegacyId,
            Name,
            Mode,
            AssemblyType,
            QuestionLimit,
            DurationMinutes,
            TotalScore,
            PassScore,
            Sections,
            Rules,
            AccessRules,
            Status,
            Order);
    }
}

public sealed class ImportTemplateQueryDto
{
    [Required]
    [StringLength(50)]
    public string ImportType { get; set; } = string.Empty;

    [StringLength(10)]
    public string? Format { get; set; }
}
