// EN: Shop aggregate root.
// VI: Aggregate root Shop.

using System.Text.RegularExpressions;
using MerchantService.Domain.Events;
using MerchantService.Domain.Exceptions;
using MerchantService.Domain.SeedWork;

namespace MerchantService.Domain.AggregatesModel.ShopAggregate;

/// <summary>
/// EN: Shop aggregate root - represents a store owned by a merchant.
/// VI: Aggregate root Shop - đại diện cho cửa hàng thuộc sở hữu của merchant.
/// </summary>
public partial class Shop : Entity, IAggregateRoot
{
    // EN: Private fields for encapsulation
    // VI: Fields private để đóng gói
    private Guid _merchantId;
    private string _name = null!;
    private string _slug = null!;
    private ShopType _type = null!;
    private BusinessCategory _category = null!;
    private ShopStatus _status = null!;
    private ContactInfo _contactInfo = null!;
    private OperatingHours? _operatingHours;
    private string? _description;
    private string? _logoUrl;
    private string? _coverImageUrl;
    private DateTime _createdAt;
    private DateTime? _updatedAt;
    private bool _isDeleted;
    private ShopFeatures _features = null!;

    private bool _isDefault;

    private readonly List<ShopBranch> _branches = new();

    /// <summary>
    /// EN: Parent merchant ID.
    /// VI: ID merchant cha.
    /// </summary>
    public Guid MerchantId => _merchantId;

    /// <summary>
    /// EN: Shop name.
    /// VI: Tên shop.
    /// </summary>
    public string Name => _name;

    /// <summary>
    /// EN: URL-friendly unique identifier.
    /// VI: Định danh duy nhất thân thiện URL.
    /// </summary>
    public string Slug => _slug;

    /// <summary>
    /// EN: Shop type (Online, Physical, Hybrid).
    /// VI: Loại shop (Online, Cửa hàng vật lý, Hybrid).
    /// </summary>
    public ShopType Type => _type;

    /// <summary>
    /// EN: Type ID for EF Core mapping.
    /// VI: Type ID cho EF Core mapping.
    /// </summary>
    public int TypeId { get; private set; }

    /// <summary>
    /// EN: Business category.
    /// VI: Ngành nghề kinh doanh.
    /// </summary>
    public BusinessCategory Category => _category;

    /// <summary>
    /// EN: Category ID for EF Core mapping.
    /// VI: Category ID cho EF Core mapping.
    /// </summary>
    public int CategoryId { get; private set; }

    /// <summary>
    /// EN: Current shop status.
    /// VI: Trạng thái shop hiện tại.
    /// </summary>
    public ShopStatus Status => _status;

    /// <summary>
    /// EN: Status ID for EF Core mapping.
    /// VI: Status ID cho EF Core mapping.
    /// </summary>
    public int StatusId { get; private set; }

    /// <summary>
    /// EN: Contact information.
    /// VI: Thông tin liên hệ.
    /// </summary>
    public ContactInfo ContactInfo => _contactInfo;

    /// <summary>
    /// EN: Operating hours.
    /// VI: Giờ hoạt động.
    /// </summary>
    public OperatingHours? OperatingHours => _operatingHours;

    /// <summary>
    /// EN: Shop description.
    /// VI: Mô tả shop.
    /// </summary>
    public string? Description => _description;

    /// <summary>
    /// EN: Shop logo URL.
    /// VI: URL logo shop.
    /// </summary>
    public string? LogoUrl => _logoUrl;

    /// <summary>
    /// EN: Cover image URL.
    /// VI: URL ảnh bìa.
    /// </summary>
    public string? CoverImageUrl => _coverImageUrl;

    /// <summary>
    /// EN: Feature configuration for multi-vertical.
    /// VI: Cấu hình tính năng cho đa ngành hàng.
    /// </summary>
    public ShopFeatures Features => _features;

    /// <summary>
    /// EN: Whether this is the default/primary shop for the merchant.
    /// VI: Shop này có phải là shop mặc định/chính của merchant không.
    /// </summary>
    public bool IsDefault => _isDefault;

    /// <summary>
    /// EN: Physical branches of the shop.
    /// VI: Các chi nhánh vật lý của shop.
    /// </summary>
    public IReadOnlyCollection<ShopBranch> Branches => _branches.AsReadOnly();

    /// <summary>
    /// EN: Creation timestamp.
    /// VI: Thời gian tạo.
    /// </summary>
    public DateTime CreatedAt => _createdAt;

    /// <summary>
    /// EN: Last update timestamp.
    /// VI: Thời gian cập nhật cuối.
    /// </summary>
    public DateTime? UpdatedAt => _updatedAt;

    /// <summary>
    /// EN: Soft delete flag.
    /// VI: Cờ xóa mềm.
    /// </summary>
    public bool IsDeleted => _isDeleted;

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    protected Shop()
    {
        _contactInfo = ContactInfo.Empty;
        _features = ShopFeatures.Empty;
    }

    /// <summary>
    /// EN: Create a new shop.
    /// VI: Tạo shop mới.
    /// </summary>
    public Shop(
        Guid merchantId,
        string name,
        string slug,
        ShopType type,
        BusinessCategory category)
    {
        if (merchantId == Guid.Empty)
            throw new DomainException("Merchant ID cannot be empty");
        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("Shop name cannot be empty");
        if (string.IsNullOrWhiteSpace(slug))
            throw new DomainException("Shop slug cannot be empty");
        if (!IsValidSlug(slug))
            throw new DomainException("Slug must contain only lowercase letters, numbers, and hyphens");
        ArgumentNullException.ThrowIfNull(type, nameof(type));
        ArgumentNullException.ThrowIfNull(category, nameof(category));

        Id = Guid.NewGuid();
        _merchantId = merchantId;
        _name = name.Trim();
        _slug = slug.ToLowerInvariant().Trim();
        _type = type;
        TypeId = type.Id;
        _category = category;
        CategoryId = category.Id;
        _status = ShopStatus.Draft;
        StatusId = ShopStatus.Draft.Id;
        _contactInfo = ContactInfo.Empty;
        _features = ShopFeatures.ForCategory(category);
        _createdAt = DateTime.UtcNow;

        AddDomainEvent(new ShopCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Update basic shop information.
    /// VI: Cập nhật thông tin cơ bản của shop.
    /// </summary>
    public void UpdateInfo(string name, string? description)
    {
        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("Shop name cannot be empty");

        _name = name.Trim();
        _description = description?.Trim();
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update shop slug.
    /// VI: Cập nhật slug của shop.
    /// </summary>
    public void UpdateSlug(string slug)
    {
        if (string.IsNullOrWhiteSpace(slug))
            throw new DomainException("Shop slug cannot be empty");
        if (!IsValidSlug(slug))
            throw new DomainException("Slug must contain only lowercase letters, numbers, and hyphens");

        _slug = slug.ToLowerInvariant().Trim();
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update contact information.
    /// VI: Cập nhật thông tin liên hệ.
    /// </summary>
    public void UpdateContactInfo(ContactInfo contactInfo)
    {
        _contactInfo = contactInfo ?? ContactInfo.Empty;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update operating hours.
    /// VI: Cập nhật giờ hoạt động.
    /// </summary>
    public void UpdateOperatingHours(OperatingHours? hours)
    {
        _operatingHours = hours;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update shop images.
    /// VI: Cập nhật hình ảnh shop.
    /// </summary>
    public void UpdateImages(string? logoUrl, string? coverImageUrl)
    {
        _logoUrl = logoUrl;
        _coverImageUrl = coverImageUrl;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update feature configuration.
    /// VI: Cập nhật cấu hình tính năng.
    /// </summary>
    public void UpdateFeatures(ShopFeatures features)
    {
        _features = features ?? ShopFeatures.Empty;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Publish shop (make it visible to customers).
    /// VI: Công khai shop (hiển thị với khách hàng).
    /// </summary>
    public void Publish()
    {
        // EN: Use StatusId (persisted int) instead of _status (may be null when EF loads entity).
        // VI: Dùng StatusId (int đã persist) thay vì _status (có thể null khi EF load entity).
        if (StatusId != ShopStatus.Draft.Id && StatusId != ShopStatus.Inactive.Id)
            throw new DomainException($"Cannot publish shop with status ID {StatusId}");

        _status = ShopStatus.Active;
        StatusId = ShopStatus.Active.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ShopPublishedDomainEvent(this));
    }

    /// <summary>
    /// EN: Set shop to inactive.
    /// VI: Đặt shop thành không hoạt động.
    /// </summary>
    public void SetInactive()
    {
        if (StatusId == ShopStatus.Closed.Id)
            throw new DomainException("Cannot change status of closed shop");

        _status = ShopStatus.Inactive;
        StatusId = ShopStatus.Inactive.Id;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Close shop permanently.
    /// VI: Đóng cửa shop vĩnh viễn.
    /// </summary>
    public void Close()
    {
        _status = ShopStatus.Closed;
        StatusId = ShopStatus.Closed.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ShopClosedDomainEvent(this));
    }

    /// <summary>
    /// EN: Add a physical branch to the shop.
    /// VI: Thêm chi nhánh vật lý cho shop.
    /// </summary>
    public ShopBranch AddBranch(string name, Address address, GeoLocation? location = null)
    {
        if (!_type.SupportsBranches)
            throw new DomainException("Online-only shops cannot have physical branches");

        var branch = new ShopBranch(Id, name, address, location);
        _branches.Add(branch);
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ShopBranchAddedDomainEvent(this, branch));
        return branch;
    }

    /// <summary>
    /// EN: Remove a branch.
    /// VI: Xóa chi nhánh.
    /// </summary>
    public void RemoveBranch(Guid branchId)
    {
        var branch = _branches.FirstOrDefault(b => b.Id == branchId);
        if (branch == null)
            throw new DomainException("Branch not found");

        _branches.Remove(branch);
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set this shop as the default/primary shop for the merchant.
    /// VI: Đặt shop này làm shop mặc định/chính của merchant.
    /// </summary>
    public void SetAsDefault()
    {
        if (_isDeleted)
            throw new DomainException("Cannot set deleted shop as default");
        if (_status == ShopStatus.Closed)
            throw new DomainException("Cannot set closed shop as default");

        _isDefault = true;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ShopSetAsDefaultDomainEvent(this));
    }

    /// <summary>
    /// EN: Clear the default flag on this shop.
    /// VI: Xóa cờ mặc định trên shop này.
    /// </summary>
    public void ClearDefault()
    {
        _isDefault = false;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Transfer ownership of this shop to another merchant.
    /// VI: Chuyển quyền sở hữu shop này cho merchant khác.
    /// </summary>
    /// <param name="newMerchantId">New owner merchant ID / ID merchant chủ mới</param>
    public void TransferOwnership(Guid newMerchantId)
    {
        if (newMerchantId == Guid.Empty)
            throw new DomainException("New merchant ID cannot be empty");
        if (newMerchantId == _merchantId)
            throw new DomainException("Cannot transfer shop to the same merchant");
        if (_isDeleted)
            throw new DomainException("Cannot transfer deleted shop");
        if (_status == ShopStatus.Closed)
            throw new DomainException("Cannot transfer closed shop");

        var previousMerchantId = _merchantId;
        _merchantId = newMerchantId;
        _isDefault = false; // EN: Clear default when transferring / VI: Xóa mặc định khi chuyển
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new ShopTransferredDomainEvent(this, previousMerchantId, newMerchantId));
    }

    /// <summary>
    /// EN: Soft delete shop.
    /// VI: Xóa mềm shop.
    /// </summary>
    public void Delete()
    {
        if (_isDeleted)
            throw new DomainException("Shop is already deleted");

        _isDeleted = true;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Validate slug format.
    /// VI: Kiểm tra định dạng slug.
    /// </summary>
    private static bool IsValidSlug(string slug)
    {
        return SlugRegex().IsMatch(slug);
    }

    [GeneratedRegex(@"^[a-z0-9]+(?:-[a-z0-9]+)*$")]
    private static partial Regex SlugRegex();
}
