/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

// 该类所属的包名，表明其位于商城API的控制器包下，主要用于处理与搜索相关的各种接口请求及对应的业务逻辑，例如热搜查询、商品搜索等功能。
package com.yami.shop.api.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.bean.dto.HotSearchDto;
import com.yami.shop.bean.dto.SearchProdDto;
import com.yami.shop.service.HotSearchService;
import com.yami.shop.service.ProductService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import com.yami.shop.common.response.ServerResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;

/**
 * SearchController类是一个Spring RESTful风格的控制器，专门用于处理与搜索相关的操作接口，为前端应用提供了诸如查询店铺热搜、全局热搜以及分页排序搜索商品等功能的后端服务支持，
 * 通过整合HotSearchService和ProductService等服务类来实现具体的业务逻辑，并借助Swagger注解对接口进行详细的文档描述，方便接口的使用和维护。
 *
 * @author lanhai
 */
@RestController
// 定义该控制器类的基础请求路径，所有该类中的接口请求路径都将以此为前缀，表明是与搜索相关的操作接口。
@RequestMapping("/search")
// 使用Swagger的@Tag注解对该控制器类进行标记，用于在API文档中生成对应的分类标签，方便接口文档的分类展示和阅读，这里表示该类下的接口都属于“搜索接口”这一分类。
@Tag(name = "搜索接口")
// 使用lombok的@AllArgsConstructor注解，自动生成包含所有final字段的构造函数，方便依赖注入，这里会为HotSearchService和ProductService生成对应的构造函数参数，以便在类中使用这两个服务类的实例。
@AllArgsConstructor
public class SearchController {

    // 通过构造函数注入HotSearchService实例，用于调用与热搜相关的业务逻辑方法，比如根据店铺ID或获取全局热搜等操作来获取热搜数据。
    private final HotSearchService hotSearchService;

    // 通过构造函数注入ProductService实例，用于调用与商品搜索相关的业务逻辑方法，例如根据商品名、排序条件等进行分页搜索商品并获取相应的商品搜索结果数据。
    private final ProductService productService;

    /**
     * 根据店铺ID获取热搜的接口方法。
     * 根据传入的店铺ID（shopId）、要获取的热搜数量（number）以及是否按照顺序排序的标识（sort），调用HotSearchService的getHotSearchDtoByShopId方法获取对应店铺的热搜数据列表，
     * 然后经过进一步处理（通过调用getListResponseEntity方法），将符合条件的热搜数据封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param shopId 要查询热搜的店铺的唯一标识符，通过请求参数传入，是必须提供的参数，用于定位具体店铺的热搜数据。
     * @param number 要获取的热搜数量，通过请求参数传入，是必须提供的参数，用于限定返回的热搜数据的条数。
     * @param sort 表示是否按照顺序排序的标识，通过请求参数传入，取值为0表示不按照顺序（随机排序），取值为1表示按照顺序排序，用于控制返回的热搜数据的排序方式。
     * @return 返回包含符合条件的热搜数据列表的ServerResponseEntity，成功时其数据部分为List<HotSearchDto>类型，该类型包含了热搜相关的详细信息（具体信息由HotSearchDto类定义）。
     */
    @GetMapping("/hotSearchByShopId")
    // 使用Swagger的@Operation注解对该接口方法进行描述，用于在API文档中生成对应的接口说明信息，这里简要说明了该接口的功能是查看店铺热搜。
    @Operation(summary = "查看店铺热搜", description = "根据店铺id,热搜数量获取热搜")
    // 使用Swagger的@Parameters注解对接口方法的多个参数进行统一描述，通过包含多个@Parameter注解来分别详细说明每个参数的名称、描述以及是否必填等信息，方便在API文档中展示参数详情。
    @Parameters({
            @Parameter(name = "shopId", description = "店铺id", required = true),
            @Parameter(name = "number", description = "取数", required = true),
            @Parameter(name = "sort", description = "是否按照顺序(0 否 1是)")
    })
    public ServerResponseEntity<List<HotSearchDto>> hotSearchByShopId(Long shopId, Integer number, Integer sort) {
        List<HotSearchDto> list = hotSearchService.getHotSearchDtoByShopId(shopId);

        return getListResponseEntity(number, sort, list);
    }

    /**
     * 获取全局热搜的接口方法。
     * 根据传入的要获取的热搜数量（number）以及是否按照顺序排序的标识（sort），调用HotSearchService的getHotSearchDtoByShopId方法并传入固定的店铺ID值0L（表示全局，从代码逻辑推测）获取全局热搜数据列表，
     * 然后经过进一步处理（通过调用getListResponseEntity方法），将符合条件的热搜数据封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param number 要获取的热搜数量，通过请求参数传入，是必须提供的参数，用于限定返回的热搜数据的条数。
     * @param sort 表示是否按照顺序排序的标识，通过请求参数传入，取值为0表示不按照顺序（随机排序），取值为1表示按照顺序排序，用于控制返回的热搜数据的排序方式。
     * @return 返回包含符合条件的热搜数据列表的ServerResponseEntity，成功时其数据部分为List<HotSearchDto>类型，该类型包含了热搜相关的详细信息（具体信息由HotSearchDto类定义）。
     */
    @GetMapping("/hotSearch")
    @Operation(summary = "查看全局热搜", description = "根据店铺id,热搜数量获取热搜")
    @Parameters({
            @Parameter(name = "number", description = "取数", required = true),
            @Parameter(name = "sort", description = "是否按照顺序(0 否 1是)", required = false)
    })
    public ServerResponseEntity<List<HotSearchDto>> hotSearch(Integer number, Integer sort) {
        List<HotSearchDto> list = hotSearchService.getHotSearchDtoByShopId(0L);
        return getListResponseEntity(number, sort, list);
    }

    /**
     * 处理热搜数据列表并返回合适响应实体的私有方法。
     * 根据传入的要获取的数量（number）、排序标识（sort）以及原始的热搜数据列表（list），进行如下处理：
     * 如果排序标识为null或者取值为0（表示不按照顺序排序），则对列表进行随机打乱操作（使用Collections.shuffle方法）；
     * 接着判断如果列表为空或者列表元素个数小于要获取的数量，直接将原始列表封装在ServerResponseEntity中返回；
     * 如果列表元素个数大于等于要获取的数量，则截取列表的前number个元素封装在ServerResponseEntity中返回，用于统一的接口响应格式处理，返回符合条件的热搜数据列表。
     *
     * @param number 要获取的数量，用于控制最终返回的热搜数据列表的元素个数。
     * @param sort 排序标识，用于判断是否对列表进行随机打乱操作以及确定返回的列表元素顺序情况。
     * @param list 原始的热搜数据列表，包含了从服务层获取到的所有热搜相关信息（具体由HotSearchDto类定义），需要根据条件进行处理后返回合适的数据子集。
     * @return 返回包含经过处理后符合条件的热搜数据列表的ServerResponseEntity，成功时其数据部分为List<HotSearchDto>类型。
     */
    private ServerResponseEntity<List<HotSearchDto>> getListResponseEntity(Integer number, Integer sort, List<HotSearchDto> list) {
        if (sort == null || sort == 0) {
            Collections.shuffle(list);
        }
        if (!CollectionUtil.isNotEmpty(list) || list.size() < number) {
            return ServerResponseEntity.success(list);
        }
        return ServerResponseEntity.success(list.subList(0, number));
    }

    /**
     * 分页排序搜索商品的接口方法。
     * 根据传入的分页参数（page）、商品名称（prodName）、排序方式（sort）、排序顺序（orderBy）以及店铺ID（shopId），调用ProductService的getSearchProdDtoPageByProdName方法进行分页排序搜索商品操作，
     * 获取到符合条件的分页商品搜索结果数据（IPage<SearchProdDto>类型），最后将该分页数据封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param page 分页参数对象，包含页码、每页数量等信息，用于进行分页查询操作，通过该参数可以获取指定页的商品搜索结果数据。
     * @param prodName 要搜索的商品名称，通过请求参数传入，是必须提供的参数，用于根据商品名称进行模糊匹配搜索商品。
     * @param sort 表示排序方式的参数，通过请求参数传入，取值为0表示默认排序，取值为1表示按照销量排序，取值为2表示按照价格排序，用于控制搜索结果中商品的排序方式。
     * @param orderBy 表示排序顺序的参数，通过请求参数传入，取值为0表示升序排序，取值为1表示降序排序，用于进一步明确排序的顺序情况，与sort参数配合使用来确定最终的商品排序规则。
     * @param shopId 要搜索商品所在店铺的唯一标识符，通过请求参数传入，是必须提供的参数，用于限定搜索的范围在指定店铺内进行。
     * @return 返回包含分页排序后的商品搜索结果数据的ServerResponseEntity，成功时其数据部分为IPage<SearchProdDto>类型，该类型包含了分页后的商品列表数据以及分页相关的元数据信息（如总页数、总记录数等）。
     */
    @GetMapping("/searchProdPage")
    @Operation(summary = "分页排序搜索商品", description = "根据商品名搜索")
    @Parameters({
            @Parameter(name = "prodName", description = "商品名", required = true),
            @Parameter(name = "orderBy", description = "排序(0升序 1降序)"),
            @Parameter(name = "shopId", description = "店铺id", required = true),
            @Parameter(name = "sort", description = "排序(0 默认排序 1销量排序 2价格排序)")
    })
    public ServerResponseEntity<IPage<SearchProdDto>> searchProdPage(PageParam page, String prodName, Integer sort, Integer orderBy, Long shopId) {

        return ServerResponseEntity.success(productService.getSearchProdDtoPageByProdName(page, prodName, sort, orderBy));
    }
}