using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Products.Enums;

namespace TakeoutSaaS.Domain.Products.Repositories;

/// <summary>
/// 商品聚合仓储契约。
/// </summary>
public interface IProductRepository
{
    /// <summary>
    /// 依据标识获取商品。
    /// </summary>
    Task<Product?> FindByIdAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按分类与状态筛选商品列表。
    /// </summary>
    Task<IReadOnlyList<Product>> SearchAsync(long tenantId, long? storeId, long? categoryId, ProductStatus? status, CancellationToken cancellationToken = default, DateTime? updatedAfter = null);

    /// <summary>
    /// 分页查询商品列表。
    /// </summary>
    Task<(IReadOnlyList<Product> Items, int Total)> SearchPagedAsync(
        ProductSearchFilter filter,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取租户下的商品分类。
    /// </summary>
    Task<IReadOnlyList<ProductCategory>> GetCategoriesAsync(long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取门店商品分类。
    /// </summary>
    Task<IReadOnlyList<ProductCategory>> GetCategoriesByStoreAsync(long tenantId, long storeId, bool onlyEnabled = true, CancellationToken cancellationToken = default);

    /// <summary>
    /// 依据标识读取分类。
    /// </summary>
    Task<ProductCategory?> FindCategoryByIdAsync(long categoryId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 判断门店内分类名称是否已存在。
    /// </summary>
    Task<bool> ExistsCategoryNameAsync(long tenantId, long storeId, string name, long? excludeCategoryId = null, CancellationToken cancellationToken = default);

    /// <summary>
    /// 统计分类下商品数量。
    /// </summary>
    Task<Dictionary<long, int>> CountProductsByCategoryIdsAsync(long tenantId, long storeId, IReadOnlyCollection<long> categoryIds, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按门店读取规格做法模板。
    /// </summary>
    Task<IReadOnlyList<ProductSpecTemplate>> GetSpecTemplatesByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按门店读取加料模板。
    /// </summary>
    Task<IReadOnlyList<ProductSpecTemplate>> GetAddonTemplatesByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按门店读取商品标签。
    /// </summary>
    Task<IReadOnlyList<ProductLabel>> GetLabelsByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按门店读取商品时段规则。
    /// </summary>
    Task<IReadOnlyList<ProductSchedule>> GetSchedulesByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 依据标识读取规格做法模板。
    /// </summary>
    Task<ProductSpecTemplate?> FindSpecTemplateByIdAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 依据标识读取加料模板。
    /// </summary>
    Task<ProductSpecTemplate?> FindAddonTemplateByIdAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 依据标识读取商品标签。
    /// </summary>
    Task<ProductLabel?> FindLabelByIdAsync(long labelId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 依据标识读取商品时段规则。
    /// </summary>
    Task<ProductSchedule?> FindScheduleByIdAsync(long scheduleId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 判断门店内模板名称是否已存在。
    /// </summary>
    Task<bool> ExistsSpecTemplateNameAsync(long tenantId, long storeId, string name, long? excludeTemplateId = null, CancellationToken cancellationToken = default);

    /// <summary>
    /// 判断门店内加料模板名称是否已存在。
    /// </summary>
    Task<bool> ExistsAddonTemplateNameAsync(long tenantId, long storeId, string name, long? excludeTemplateId = null, CancellationToken cancellationToken = default);

    /// <summary>
    /// 判断门店内商品标签名称是否已存在。
    /// </summary>
    Task<bool> ExistsLabelNameAsync(long tenantId, long storeId, string name, long? excludeLabelId = null, CancellationToken cancellationToken = default);

    /// <summary>
    /// 判断门店内时段规则名称是否已存在。
    /// </summary>
    Task<bool> ExistsScheduleNameAsync(long tenantId, long storeId, string name, long? excludeScheduleId = null, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按模板读取规格做法选项。
    /// </summary>
    Task<IReadOnlyList<ProductSpecTemplateOption>> GetSpecTemplateOptionsByTemplateIdsAsync(IReadOnlyCollection<long> templateIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按模板读取模板关联商品。
    /// </summary>
    Task<IReadOnlyList<ProductSpecTemplateProduct>> GetSpecTemplateProductsByTemplateIdsAsync(IReadOnlyCollection<long> templateIds, long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 统计标签关联商品数量。
    /// </summary>
    Task<Dictionary<long, int>> CountLabelProductsByLabelIdsAsync(long tenantId, long storeId, IReadOnlyCollection<long> labelIds, CancellationToken cancellationToken = default);

    /// <summary>
    /// 读取时段规则关联商品。
    /// </summary>
    Task<IReadOnlyList<ProductScheduleProduct>> GetScheduleProductsByScheduleIdsAsync(IReadOnlyCollection<long> scheduleIds, long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 过滤门店内真实存在的商品 ID。
    /// </summary>
    Task<IReadOnlyList<long>> FilterExistingProductIdsAsync(long tenantId, long storeId, IReadOnlyCollection<long> productIds, CancellationToken cancellationToken = default);

    /// <summary>
    /// 查询商品选择器列表。
    /// </summary>
    Task<IReadOnlyList<Product>> SearchPickerAsync(long tenantId, long storeId, long? categoryId, string? keyword, int limit, CancellationToken cancellationToken = default);

    /// <summary>
    /// 按标识批量读取商品。
    /// </summary>
    Task<IReadOnlyList<Product>> GetByIdsAsync(
        long tenantId,
        long storeId,
        IReadOnlyCollection<long> productIds,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量更新商品分类。
    /// </summary>
    Task<int> BatchUpdateProductCategoryAsync(long tenantId, long storeId, long categoryId, IReadOnlyCollection<long> productIds, CancellationToken cancellationToken = default);

    /// <summary>
    /// 单商品换绑分类。
    /// </summary>
    Task<bool> MoveProductToCategoryAsync(long tenantId, long storeId, long fromCategoryId, long toCategoryId, long productId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品 SKU。
    /// </summary>
    Task<IReadOnlyList<ProductSku>> GetSkusAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品 SKU。
    /// </summary>
    Task<IReadOnlyList<ProductSku>> GetSkusByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品套餐分组。
    /// </summary>
    Task<IReadOnlyList<ProductComboGroup>> GetComboGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品套餐分组。
    /// </summary>
    Task<IReadOnlyList<ProductComboGroup>> GetComboGroupsByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取套餐分组内商品。
    /// </summary>
    Task<IReadOnlyList<ProductComboGroupItem>> GetComboGroupItemsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取套餐分组内商品。
    /// </summary>
    Task<IReadOnlyList<ProductComboGroupItem>> GetComboGroupItemsByGroupIdsAsync(IReadOnlyCollection<long> comboGroupIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品加料组与选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>加料组集合。</returns>
    Task<IReadOnlyList<ProductAddonGroup>> GetAddonGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品加料组。
    /// </summary>
    Task<IReadOnlyList<ProductAddonGroup>> GetAddonGroupsByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品加料选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>加料选项集合。</returns>
    Task<IReadOnlyList<ProductAddonOption>> GetAddonOptionsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品加料选项。
    /// </summary>
    Task<IReadOnlyList<ProductAddonOption>> GetAddonOptionsByGroupIdsAsync(IReadOnlyCollection<long> addonGroupIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品规格组与选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>规格组集合。</returns>
    Task<IReadOnlyList<ProductAttributeGroup>> GetAttributeGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品规格组。
    /// </summary>
    Task<IReadOnlyList<ProductAttributeGroup>> GetAttributeGroupsByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品规格选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>规格选项集合。</returns>
    Task<IReadOnlyList<ProductAttributeOption>> GetAttributeOptionsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品规格选项。
    /// </summary>
    Task<IReadOnlyList<ProductAttributeOption>> GetAttributeOptionsByGroupIdsAsync(IReadOnlyCollection<long> attributeGroupIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品媒资。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>媒资列表。</returns>
    Task<IReadOnlyList<ProductMediaAsset>> GetMediaAssetsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品媒资。
    /// </summary>
    Task<IReadOnlyList<ProductMediaAsset>> GetMediaAssetsByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 获取商品定价规则。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>定价规则集合。</returns>
    Task<IReadOnlyList<ProductPricingRule>> GetPricingRulesAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量获取商品定价规则。
    /// </summary>
    Task<IReadOnlyList<ProductPricingRule>> GetPricingRulesByProductIdsAsync(IReadOnlyCollection<long> productIds, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增分类。
    /// </summary>
    /// <param name="category">分类实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddCategoryAsync(ProductCategory category, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增规格做法模板。
    /// </summary>
    Task AddSpecTemplateAsync(ProductSpecTemplate template, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增规格做法模板选项。
    /// </summary>
    Task AddSpecTemplateOptionsAsync(IEnumerable<ProductSpecTemplateOption> options, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增规格做法模板关联商品。
    /// </summary>
    Task AddSpecTemplateProductsAsync(IEnumerable<ProductSpecTemplateProduct> relations, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增商品标签。
    /// </summary>
    Task AddLabelAsync(ProductLabel label, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增时段规则。
    /// </summary>
    Task AddScheduleAsync(ProductSchedule schedule, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增时段规则关联商品。
    /// </summary>
    Task AddScheduleProductsAsync(IEnumerable<ProductScheduleProduct> relations, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增商品。
    /// </summary>
    /// <param name="product">商品实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddProductAsync(Product product, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增 SKU。
    /// </summary>
    /// <param name="skus">SKU 集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddSkusAsync(IEnumerable<ProductSku> skus, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增套餐分组与分组商品。
    /// </summary>
    /// <param name="groups">套餐分组集合。</param>
    /// <param name="items">分组商品集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddComboGroupsAsync(IEnumerable<ProductComboGroup> groups, IEnumerable<ProductComboGroupItem> items, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增加料组与选项。
    /// </summary>
    /// <param name="groups">加料组集合。</param>
    /// <param name="options">加料选项集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddAddonGroupsAsync(IEnumerable<ProductAddonGroup> groups, IEnumerable<ProductAddonOption> options, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增规格组与选项。
    /// </summary>
    /// <param name="groups">规格组集合。</param>
    /// <param name="options">规格选项集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddAttributeGroupsAsync(IEnumerable<ProductAttributeGroup> groups, IEnumerable<ProductAttributeOption> options, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增媒资。
    /// </summary>
    /// <param name="assets">媒资集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddMediaAssetsAsync(IEnumerable<ProductMediaAsset> assets, CancellationToken cancellationToken = default);

    /// <summary>
    /// 新增定价规则。
    /// </summary>
    /// <param name="rules">定价规则集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task AddPricingRulesAsync(IEnumerable<ProductPricingRule> rules, CancellationToken cancellationToken = default);

    /// <summary>
    /// 持久化变更。
    /// </summary>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task SaveChangesAsync(CancellationToken cancellationToken = default);

    /// <summary>
    /// 更新商品。
    /// </summary>
    /// <param name="product">商品实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task UpdateProductAsync(Product product, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task DeleteProductAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 更新分类。
    /// </summary>
    /// <param name="category">分类实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task UpdateCategoryAsync(ProductCategory category, CancellationToken cancellationToken = default);

    /// <summary>
    /// 更新规格做法模板。
    /// </summary>
    Task UpdateSpecTemplateAsync(ProductSpecTemplate template, CancellationToken cancellationToken = default);

    /// <summary>
    /// 更新商品标签。
    /// </summary>
    Task UpdateLabelAsync(ProductLabel label, CancellationToken cancellationToken = default);

    /// <summary>
    /// 更新时段规则。
    /// </summary>
    Task UpdateScheduleAsync(ProductSchedule schedule, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除分类。
    /// </summary>
    /// <param name="categoryId">分类 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task DeleteCategoryAsync(long categoryId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除规格做法模板。
    /// </summary>
    Task DeleteSpecTemplateAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品标签。
    /// </summary>
    Task DeleteLabelAsync(long labelId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除时段规则。
    /// </summary>
    Task DeleteScheduleAsync(long scheduleId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品下的 SKU。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemoveSkusAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品下的套餐分组及分组商品。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemoveComboGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除模板下的规格做法选项。
    /// </summary>
    Task RemoveSpecTemplateOptionsAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除模板关联商品。
    /// </summary>
    Task RemoveSpecTemplateProductsAsync(long templateId, long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除标签关联商品。
    /// </summary>
    Task RemoveLabelProductsAsync(long labelId, long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除时段规则关联商品。
    /// </summary>
    Task RemoveScheduleProductsAsync(long scheduleId, long tenantId, long storeId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品下的加料组及选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemoveAddonGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品下的规格组及选项。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemoveAttributeGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品媒资。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemoveMediaAssetsAsync(long productId, long tenantId, CancellationToken cancellationToken = default);

    /// <summary>
    /// 删除商品定价规则。
    /// </summary>
    /// <param name="productId">商品 ID。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    Task RemovePricingRulesAsync(long productId, long tenantId, CancellationToken cancellationToken = default);
}

/// <summary>
/// 商品分页查询过滤条件。
/// </summary>
public sealed record ProductSearchFilter
{
    /// <summary>
    /// 租户 ID。
    /// </summary>
    public long TenantId { get; init; }

    /// <summary>
    /// 门店 ID（可选）。
    /// </summary>
    public long? StoreId { get; init; }

    /// <summary>
    /// 分类 ID（可选）。
    /// </summary>
    public long? CategoryId { get; init; }

    /// <summary>
    /// 状态过滤。
    /// </summary>
    public ProductStatus? Status { get; init; }

    /// <summary>
    /// 商品类型过滤。
    /// </summary>
    public ProductKind? Kind { get; init; }

    /// <summary>
    /// 关键字（名称/SPU）。
    /// </summary>
    public string? Keyword { get; init; }

    /// <summary>
    /// 是否仅沽清商品。
    /// </summary>
    public bool? IsSoldOut { get; init; }

    /// <summary>
    /// 页码（从 1 开始）。
    /// </summary>
    public int Page { get; init; } = 1;

    /// <summary>
    /// 每页条数。
    /// </summary>
    public int PageSize { get; init; } = 20;

    /// <summary>
    /// 排序字段（name/price/status/createdAt）。
    /// </summary>
    public string? SortBy { get; init; }

    /// <summary>
    /// 是否倒序。
    /// </summary>
    public bool SortDescending { get; init; } = true;
}
