using AyCode.Core.Extensions;
using AyCode.Core.Interfaces;
using AyCode.Core.Serializers.Attributes;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Serializers.Jsons;
using MemoryPack;
using MessagePack;
using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json;

namespace AyCode.Core.Tests.TestModels;

#region Shared Reference Base Types

public abstract class SharedTagBase : IId<int>
{
    [Key(0)]
    public int Id { get; set; }
    [Key(1)]
    public string Name { get; set; } = "";
    [AcStringIntern(true)]
    [Key(2)]
    public string Color { get; set; } = "#000000";
    [Key(3)]
    public int Priority { get; set; }
    [Key(4)]
    public bool IsActive { get; set; } = true;
    [Key(5)]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    [Key(6)]
    public string? Description { get; set; }
}

public abstract class SharedCategoryBase : IId<int>
{
    [Key(0)]
    public int Id { get; set; }
    [Key(1)]
    public string Name { get; set; } = "";
    [Key(2)]
    public string? Description { get; set; }
    [Key(3)]
    public int SortOrder { get; set; }
    [Key(4)]
    public bool IsDefault { get; set; }
    [Key(5)]
    public int? ParentCategoryId { get; set; }
    [Key(6)]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    [Key(7)]
    public DateTime? UpdatedAt { get; set; }
}

public abstract class SharedUserBase<TPreferences> : IId<int>
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }
    [Key(1)]
    public string Username { get; set; } = "";
    [Key(2)]
    public string Email { get; set; } = "";
    [Key(3)]
    public string FirstName { get; set; } = "";
    [Key(4)]
    public string LastName { get; set; } = "";
    [Key(5)]
    public bool IsActive { get; set; } = true;
    [Key(6)]
    public TestUserRole Role { get; set; } = TestUserRole.User;
    [Key(7)]
    public DateTime? LastLoginAt { get; set; }
    [Key(8)]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    [Key(9)]
    public TPreferences? Preferences { get; set; }
}

public abstract class UserPreferencesBase
{
    [AcStringIntern(true)]
    [Key(0)]
    public string Theme { get; set; } = "light";
    [AcStringIntern(true)]
    [Key(1)]
    public string Language { get; set; } = "en-US";
    [Key(2)]
    public bool NotificationsEnabled { get; set; } = true;
    [AcStringIntern(true)]
    [Key(3)]
    public string? EmailDigestFrequency { get; set; }
}

public abstract class MetadataInfoBase<TSelf>
    where TSelf : MetadataInfoBase<TSelf>
{
    [AcStringIntern(true)]
    [Key(0)]
    public string Key { get; set; } = "";
    [AcStringIntern(true)]
    [Key(1)]
    public string Value { get; set; } = "";
    [Key(2)]
    public DateTime Timestamp { get; set; } = DateTime.UtcNow;

    [Key(3)]
    public TSelf? ChildMetadata { get; set; }
}

#endregion

#region Order Hierarchy Base Types

public abstract class TestOrderBase<TItem, TTag, TUser, TCategory, TMetadata, TPreferences> : IId<int>
    where TItem : class
    where TTag : SharedTagBase
    where TUser : SharedUserBase<TPreferences>
    where TCategory : SharedCategoryBase
    where TMetadata : MetadataInfoBase<TMetadata>
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }

    [Key(1)]
    public string OrderNumber { get; set; } = "";

    [Key(2)]
    public TestStatus Status { get; set; } = TestStatus.Pending;

    [Key(3)]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    [Key(4)]
    public DateTime? PaidDateUtc { get; set; }

    [Key(5)]
    public decimal TotalAmount { get; set; }

    [Key(6)]
    public List<TItem> Items { get; set; } = [];

    [Key(7)]
    public TTag? PrimaryTag { get; set; }

    [Key(8)]
    public TTag? SecondaryTag { get; set; }

    [Key(9)]
    public TUser? Owner { get; set; }

    [Key(10)]
    public TCategory? Category { get; set; }

    [Key(11)]
    public List<TTag> Tags { get; set; } = [];

    [Key(12)]
    public TMetadata? OrderMetadata { get; set; }

    [Key(13)]
    public TMetadata? AuditMetadata { get; set; }

    [Key(14)]
    public List<TMetadata> MetadataList { get; set; } = [];

    [JsonNoMergeCollection]
    [Key(15)]
    public List<TItem> NoMergeItems { get; set; } = [];

    [MemoryPackIgnore]
    [JsonIgnore]
    [IgnoreMember]
    [BsonIgnore]
    public object? Parent { get; set; }
}

public abstract class TestOrderItemBase<TPallet, TTag, TUser, TMetadata, TParentOrder, TPreferences> : IId<int>
    where TPallet : class
    where TTag : SharedTagBase
    where TUser : SharedUserBase<TPreferences>
    where TMetadata : MetadataInfoBase<TMetadata>
    where TParentOrder : class
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }

    [AcStringIntern(true)]
    [Key(1)]
    public string ProductName { get; set; } = "";

    [Key(2)]
    public int Quantity { get; set; }

    [Key(3)]
    public decimal UnitPrice { get; set; }

    [Key(4)]
    public TestStatus Status { get; set; } = TestStatus.Pending;

    [Key(5)]
    public List<TPallet> Pallets { get; set; } = [];

    [Key(6)]
    public TTag? Tag { get; set; }

    [Key(7)]
    public TUser? Assignee { get; set; }

    [Key(8)]
    public TMetadata? ItemMetadata { get; set; }

    [MemoryPackIgnore]
    [JsonIgnore]
    [IgnoreMember]
    [BsonIgnore]
    public TParentOrder? ParentOrder { get; set; }
}

public abstract class TestPalletBase<TMeasurement, TTag, TUser, TCategory, TMetadata, TParentItem, TPreferences> : IId<int>
    where TMeasurement : class
    where TTag : SharedTagBase
    where TUser : SharedUserBase<TPreferences>
    where TCategory : SharedCategoryBase
    where TMetadata : MetadataInfoBase<TMetadata>
    where TParentItem : class
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }

    [Key(1)]
    public string PalletCode { get; set; } = "";

    [Key(2)]
    public int TrayCount { get; set; }

    [Key(3)]
    public TestStatus Status { get; set; } = TestStatus.Pending;

    [Key(4)]
    public double Weight { get; set; }

    [Key(5)]
    public List<TMeasurement> Measurements { get; set; } = [];

    [Key(6)]
    public TTag? Tag { get; set; }

    [Key(7)]
    public TUser? Inspector { get; set; }

    [Key(8)]
    public TCategory? Category { get; set; }

    [Key(9)]
    public TMetadata? PalletMetadata { get; set; }

    [MemoryPackIgnore]
    [JsonIgnore]
    [IgnoreMember]
    [BsonIgnore]
    public TParentItem? ParentItem { get; set; }
}

public abstract class TestMeasurementBase<TPoint, TTag, TUser, TParentPallet, TPreferences> : IId<int>
    where TPoint : class
    where TTag : SharedTagBase
    where TUser : SharedUserBase<TPreferences>
    where TParentPallet : class
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }

    [Key(1)]
    public string Name { get; set; } = "";

    [Key(2)]
    public double TotalWeight { get; set; }

    [Key(3)]
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

    [Key(4)]
    public List<TPoint> Points { get; set; } = [];

    [Key(5)]
    public TTag? Tag { get; set; }

    [Key(6)]
    public TUser? Operator { get; set; }

    [MemoryPackIgnore]
    [JsonIgnore]
    [IgnoreMember]
    [BsonIgnore]
    public TParentPallet? ParentPallet { get; set; }
}

public abstract class TestMeasurementPointBase<TTag, TUser, TParentMeasurement, TPreferences> : IId<int>
    where TTag : SharedTagBase
    where TUser : SharedUserBase<TPreferences>
    where TParentMeasurement : class
    where TPreferences : UserPreferencesBase
{
    [Key(0)]
    public int Id { get; set; }

    [Key(1)]
    public string Label { get; set; } = "";

    [Key(2)]
    public double Value { get; set; }

    [Key(3)]
    public DateTime MeasuredAt { get; set; } = DateTime.UtcNow;

    [Key(4)]
    public TTag? Tag { get; set; }

    [Key(5)]
    public TUser? Verifier { get; set; }

    [MemoryPackIgnore]
    [JsonIgnore]
    [IgnoreMember]
    [BsonIgnore]
    public TParentMeasurement? ParentMeasurement { get; set; }
}

#endregion
