using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.App.Products.Commands;
using TakeoutSaaS.Application.App.Products.Dto;
using TakeoutSaaS.Application.App.Products.Queries;
using TakeoutSaaS.Application.App.Stores.Services;
using TakeoutSaaS.Infrastructure.App.Persistence;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Web.Api;
using TakeoutSaaS.TenantApi.Contracts.Product;

namespace TakeoutSaaS.TenantApi.Controllers;

/// <summary>
/// 租户端分类管理。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/tenant/v{version:apiVersion}/product")]
public sealed class ProductCategoryController(
    IMediator mediator,
    TakeoutAppDbContext dbContext,
    StoreContextService storeContextService) : BaseApiController
{
    /// <summary>
    /// 分类列表（侧栏）。
    /// </summary>
    [HttpGet("category/list")]
    [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<ProductCategoryListItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<IReadOnlyList<ProductCategoryListItemResponse>>> GetCategoryList(
        [FromQuery] ProductCategoryListRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetProductCategoryListQuery
        {
            StoreId = storeId
        }, cancellationToken);

        return ApiResponse<IReadOnlyList<ProductCategoryListItemResponse>>.Ok(result.Select(MapCategoryListItem).ToList());
    }

    /// <summary>
    /// 分类管理列表。
    /// </summary>
    [HttpGet("category/manage/list")]
    [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>> GetCategoryManageList(
        [FromQuery] ProductCategoryManageListRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new GetProductCategoryManageListQuery
        {
            StoreId = storeId,
            Keyword = request.Keyword,
            Status = request.Status
        }, cancellationToken);

        return ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>.Ok(result.Select(MapCategoryManageItem).ToList());
    }

    /// <summary>
    /// 保存分类。
    /// </summary>
    [HttpPost("category/manage/save")]
    [ProducesResponseType(typeof(ApiResponse<ProductCategoryManageItemResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<ProductCategoryManageItemResponse>> SaveCategory(
        [FromBody] SaveProductCategoryRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new SaveProductCategoryCommand
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseSnowflakeOrNull(request.Id),
            Name = request.Name,
            Description = request.Description,
            Icon = request.Icon,
            Channels = request.Channels,
            Sort = request.Sort,
            Status = request.Status
        }, cancellationToken);

        return ApiResponse<ProductCategoryManageItemResponse>.Ok(MapCategoryManageItem(result));
    }

    /// <summary>
    /// 删除分类。
    /// </summary>
    [HttpPost("category/manage/delete")]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> DeleteCategory(
        [FromBody] DeleteProductCategoryRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        await mediator.Send(new DeleteProductCategoryCommand
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseRequiredSnowflake(request.CategoryId, nameof(request.CategoryId))
        }, cancellationToken);

        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 修改分类状态。
    /// </summary>
    [HttpPost("category/manage/status")]
    [ProducesResponseType(typeof(ApiResponse<ProductCategoryManageItemResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<ProductCategoryManageItemResponse>> ChangeCategoryStatus(
        [FromBody] ChangeProductCategoryStatusRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new ChangeProductCategoryStatusCommand
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseRequiredSnowflake(request.CategoryId, nameof(request.CategoryId)),
            Status = request.Status
        }, cancellationToken);

        return ApiResponse<ProductCategoryManageItemResponse>.Ok(MapCategoryManageItem(result));
    }

    /// <summary>
    /// 分类排序。
    /// </summary>
    [HttpPost("category/manage/sort")]
    [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>> SortCategory(
        [FromBody] SortProductCategoryRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new SortProductCategoryCommand
        {
            StoreId = storeId,
            Items = (request.Items ?? [])
                .Select(item => new SortProductCategoryItem
                {
                    CategoryId = StoreApiHelpers.ParseRequiredSnowflake(item.CategoryId, nameof(item.CategoryId)),
                    Sort = item.Sort
                })
                .ToList()
        }, cancellationToken);

        return ApiResponse<IReadOnlyList<ProductCategoryManageItemResponse>>.Ok(result.Select(MapCategoryManageItem).ToList());
    }

    /// <summary>
    /// 绑定分类商品。
    /// </summary>
    [HttpPost("category/manage/products/bind")]
    [ProducesResponseType(typeof(ApiResponse<ProductBindResultResponse>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<ProductBindResultResponse>> BindCategoryProducts(
        [FromBody] BindCategoryProductsRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new BindCategoryProductsCommand
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseRequiredSnowflake(request.CategoryId, nameof(request.CategoryId)),
            ProductIds = StoreApiHelpers.ParseSnowflakeList(request.ProductIds)
        }, cancellationToken);

        return ApiResponse<ProductBindResultResponse>.Ok(new ProductBindResultResponse
        {
            TotalCount = result.TotalCount,
            SuccessCount = result.SuccessCount,
            FailedCount = result.FailedCount
        });
    }

    /// <summary>
    /// 解绑分类商品。
    /// </summary>
    [HttpPost("category/manage/products/unbind")]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<object>> UnbindCategoryProduct(
        [FromBody] UnbindCategoryProductRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        await mediator.Send(new UnbindCategoryProductCommand
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseRequiredSnowflake(request.CategoryId, nameof(request.CategoryId)),
            ProductId = StoreApiHelpers.ParseRequiredSnowflake(request.ProductId, nameof(request.ProductId))
        }, cancellationToken);

        return ApiResponse<object>.Ok(null);
    }

    /// <summary>
    /// 商品选择器。
    /// </summary>
    [HttpGet("picker/list")]
    [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<ProductPickerItemResponse>>), StatusCodes.Status200OK)]
    public async Task<ApiResponse<IReadOnlyList<ProductPickerItemResponse>>> PickerList(
        [FromQuery] ProductPickerListRequest request,
        CancellationToken cancellationToken)
    {
        var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
        await EnsureStoreAccessibleAsync(storeId, cancellationToken);

        var result = await mediator.Send(new SearchProductPickerQuery
        {
            StoreId = storeId,
            CategoryId = StoreApiHelpers.ParseSnowflakeOrNull(request.CategoryId),
            Keyword = request.Keyword,
            Limit = request.Limit ?? 200
        }, cancellationToken);

        return ApiResponse<IReadOnlyList<ProductPickerItemResponse>>.Ok(result.Select(MapPickerItem).ToList());
    }

    private async Task EnsureStoreAccessibleAsync(long storeId, CancellationToken cancellationToken)
    {
        var (tenantId, merchantId) = StoreApiHelpers.GetTenantMerchantContext(storeContextService);
        await StoreApiHelpers.EnsureStoreAccessibleAsync(dbContext, tenantId, merchantId, storeId, cancellationToken);
    }

    private static ProductCategoryListItemResponse MapCategoryListItem(ProductCategoryListItemDto source)
    {
        return new ProductCategoryListItemResponse
        {
            Id = source.Id.ToString(),
            Name = source.Name,
            ProductCount = source.ProductCount,
            Sort = source.Sort
        };
    }

    private static ProductCategoryManageItemResponse MapCategoryManageItem(ProductCategoryManageItemDto source)
    {
        return new ProductCategoryManageItemResponse
        {
            Id = source.Id.ToString(),
            Name = source.Name,
            ProductCount = source.ProductCount,
            Sort = source.Sort,
            Description = source.Description,
            Icon = source.Icon,
            Status = source.Status,
            Channels = source.Channels.ToList()
        };
    }

    private static ProductPickerItemResponse MapPickerItem(ProductPickerItemDto source)
    {
        return new ProductPickerItemResponse
        {
            Id = source.Id.ToString(),
            CategoryId = source.CategoryId.ToString(),
            CategoryName = source.CategoryName,
            Name = source.Name,
            Price = source.Price,
            SpuCode = source.SpuCode,
            Status = source.Status
        };
    }
}
