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

package com.yami.shop.api.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.bean.app.dto.ProductDto;
import com.yami.shop.bean.app.dto.TagProductDto;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.Sku;
import com.yami.shop.bean.model.Transport;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.TransportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 商品相关接口的控制器类，用于处理与商品相关的各种查询请求，例如获取商品列表、商品详情、新品推荐、按标签获取商品列表等操作，
 * 通过调用不同的服务层方法来获取相应的数据，并以统一的响应格式返回给前端使用。
 *
 * @author lgh on 2018/11/26.
 */
@RestController
@RequestMapping("/prod")
@Tag(name = "商品接口")
public class ProdController {

    // 自动注入商品服务层接口，用于调用与商品相关的核心业务逻辑方法，如根据分类 ID 查询商品列表、获取商品详情等操作
    @Autowired
    private ProductService prodService;

    // 自动注入库存单元（SKU）服务层接口，用于获取商品对应的 SKU 相关信息，例如根据商品 ID 查询其所有的 SKU 列表等操作
    @Autowired
    private SkuService skuService;

    // 自动注入运费模板服务层接口，用于获取商品相关的运费模板信息，比如根据运费模板 ID 获取详细的运费模板及关联信息
    @Autowired
    private TransportService transportService;

    /**
     * 根据分类 ID 获取商品列表信息的方法，接收分类 ID 和分页参数，调用商品服务层的方法按照分类 ID 查询并返回符合条件的商品信息分页结果，
     * 用于前端展示某个分类下的所有商品列表，方便用户浏览和筛选商品。
     *
     * @param categoryId 要查询商品列表的分类 ID，通过请求参数传入，是必填项，用于筛选属于该分类下的商品记录
     * @param page 分页对象，包含页码、每页数量等分页相关参数，用于控制查询结果的分页展示，确保数据按照一定的数量和页码进行返回
     * @return 包含商品信息分页数据的 ServerResponseEntity，以 ProductDto 类型封装商品信息，方便前端展示和使用，若查询到数据则返回对应分页结果，否则返回相应的空数据表示
     */
    @GetMapping("/pageProd")
    @Operation(summary = "通过分类id商品列表信息", description = "根据分类ID获取该分类下所有的商品列表信息")
    @Parameters({
            @Parameter(name = "categoryId", description = "分类ID", required = true),
    })
    public ServerResponseEntity<IPage<ProductDto>> prodList(
            @RequestParam(value = "categoryId") Long categoryId, PageParam<ProductDto> page) {
        IPage<ProductDto> productPage = prodService.pageByCategoryId(page, categoryId);
        return ServerResponseEntity.success(productPage);
    }

    /**
     * 根据商品 ID 获取商品详情信息的方法，接收商品 ID，通过调用商品服务层和库存单元服务层的方法获取商品的详细信息，
     * 包括基本信息、启用的 SKU 列表以及根据商品的配送方式和运费模板 ID 判断是否需要返回运费模板信息等，最后将整合好的商品详情信息返回给前端，
     * 方便用户查看商品的详细情况以及下单时参考运费等相关信息。
     *
     * @param prodId 要查询详情的商品 ID，通过请求参数传入，是必填项，用于从数据库中精准获取对应的商品记录
     * @return 包含商品详情信息的 ServerResponseEntity，以 ProductDto 类型封装商品的详细信息，若商品不存在则返回相应的空数据表示，否则返回完整的商品详情对象
     */
    @GetMapping("/prodInfo")
    @Operation(summary = "商品详情信息", description = "根据商品ID（prodId）获取商品信息")
    @Parameter(name = "prodId", description = "商品ID", required = true)
    public ServerResponseEntity<ProductDto> prodInfo(Long prodId) {

        // 通过商品服务层的方法，根据商品 ID 从数据库中获取商品的基本信息，若商品不存在则直接返回空的成功响应（可根据实际需求优化此处逻辑，比如返回特定的错误提示）
        Product product = prodService.getProductByProdId(prodId);
        if (product == null) {
            return ServerResponseEntity.success();
        }

        // 通过库存单元服务层的方法，根据商品 ID 查询该商品对应的所有 SKU 列表
        List<Sku> skuList = skuService.listByProdId(prodId);
        // 使用 Java 8 的 Stream API 过滤出状态为启用（这里假设状态为 1 表示启用）的 SKU 列表，方便前端展示可用的商品库存单元信息
        List<Sku> useSkuList = skuList.stream().filter(sku -> sku.getStatus() == 1).collect(Collectors.toList());
        // 将启用的 SKU 列表设置到商品对象中，完善商品的详细信息
        product.setSkuList(useSkuList);

        // 使用 Hutool 的 BeanUtil 将商品对象转换为对应的 DTO 类型，方便按照前端所需的格式返回数据，避免直接暴露数据库实体对象带来的潜在风险
        ProductDto productDto = BeanUtil.copyProperties(product, ProductDto.class);

        // 将商品的配送方式字符串解析为对应的对象（这里假设使用了自定义的 JSON 解析方法，具体根据实际情况而定），方便后续判断和获取相关的配送信息
        Product.DeliveryModeVO deliveryModeVO = Json.parseObject(product.getDeliveryMode(), Product.DeliveryModeVO.class);

        // 判断如果商品有店铺配送的方式，并且商品关联的运费模板 ID 不为空（即存在运费模板），则通过运费模板服务层的方法，
        // 根据运费模板 ID 获取详细的运费模板及关联信息，并设置到商品详情的 DTO 对象中，供前端查阅运费相关情况，方便用户下单时参考运费成本
        if (deliveryModeVO.getHasShopDelivery() && product.getDeliveryTemplateId()!= null) {
            Transport transportAndAllItems = transportService.getTransportAndAllItems(product.getDeliveryTemplateId());
            productDto.setTransport(transportAndAllItems);
        }

        return ServerResponseEntity.success(productDto);
    }

    /**
     * 获取新品推荐商品列表的方法，接收分页参数，调用商品服务层的方法按照商品上架时间等条件查询并返回新品推荐的商品信息分页结果，
     * 用于前端展示最新上架的商品，方便用户发现新商品，增加商品的曝光和销售机会。
     *
     * @param page 分页对象，包含页码、每页数量等分页相关参数，用于控制查询结果的分页展示，确保数据按照一定的数量和页码进行返回
     * @return 包含新品推荐商品信息分页数据的 ServerResponseEntity，以 ProductDto 类型封装商品信息，方便前端展示和使用，若查询到数据则返回对应分页结果，否则返回相应的空数据表示
     */
    @GetMapping("/lastedProdPage")
    @Operation(summary = "新品推荐", description = "获取新品推荐商品列表")
    @Parameters({})
    public ServerResponseEntity<IPage<ProductDto>> lastedProdPage(PageParam<ProductDto> page) {
        IPage<ProductDto> productPage = prodService.pageByPutAwayTime(page);
        return ServerResponseEntity.success(productPage);
    }

    /**
     * 根据分组标签 ID 获取商品列表的方法，接收分组标签 ID 和分页参数，调用商品服务层的方法按照分组标签 ID 查询并返回符合条件的商品信息分页结果，
     * 用于前端展示属于某个分组标签下的商品列表，方便用户按照标签分类查找感兴趣的商品。
     *
     * @param tagId 要查询商品列表的分组标签 ID，通过请求参数传入，是必填项，用于筛选属于该分组标签下的商品记录
     * @param page 分页对象，包含页码、每页数量等分页相关参数，用于控制查询结果的分页展示，确保数据按照一定的数量和页码进行返回
     * @return 包含商品信息分页数据的 ServerResponseEntity，以 ProductDto 类型封装商品信息，方便前端展示和使用，若查询到数据则返回对应分页结果，否则返回相应的空数据表示
     */
    @GetMapping("/prodListByTagId")
    @Operation(summary = "通过分组标签获取商品列表", description = "通过分组标签id（tagId）获取商品列表")
    @Parameters({
            @Parameter(name = "tagId", description = "当前页，默认为1", required = true),
    })
    public ServerResponseEntity<IPage<ProductDto>> prodListByTagId(
            @RequestParam(value = "tagId") Long tagId, PageParam<ProductDto> page) {
        IPage<ProductDto> productPage = prodService.pageByTagId(page, tagId);
        return ServerResponseEntity.success(productPage);
    }

    /**
     * 获取销量最多的商品列表（每日疯抢）的方法，接收分页参数，调用商品服务层的方法按照商品销量等条件查询并返回销量较多的商品信息分页结果，
     * 用于前端展示热门商品，吸引用户购买，提高商品的销售转化率。
     *
     * @param page 分页对象，包含页码、每页数量等分页相关参数，用于控制查询结果的分页展示，确保数据按照一定的数量和页码进行返回
     * @return 包含销量最多商品信息分页数据的 ServerResponseEntity，以 ProductDto 类型封装商品信息，方便前端展示和使用，若查询到数据则返回对应分页结果，否则返回相应的空数据表示
     */
    @GetMapping("/moreBuyProdList")
    @Operation(summary = "每日疯抢", description = "获取销量最多的商品列表")
    @Parameters({})
    public ServerResponseEntity<IPage<ProductDto>> moreBuyProdList(PageParam<ProductDto> page) {
        IPage<ProductDto> productPage = prodService.moreBuyProdList(page);
        return ServerResponseEntity.success(productPage);
    }

    /**
     * 获取首页所有标签商品列表的方法，调用商品服务层的方法获取首页所有标签对应的商品列表信息，用于前端展示首页的标签商品分类情况，
     * 方便用户快速浏览不同标签下的商品，提升用户体验和商品的展示效果。
     *
     * @return 包含首页所有标签商品信息列表的 ServerResponseEntity，以 TagProductDto 类型封装商品信息，方便前端展示和使用，若查询到数据则返回对应列表，否则返回相应的空数据表示
     */
    @GetMapping("/tagProdList")
    @Operation(summary = "首页所有标签商品接口", description = "获取首页所有标签商品接口")
    public ServerResponseEntity<List<TagProductDto>> getTagProdList() {
        List<TagProductDto> productDtoList = prodService.tagProdList();
        return ServerResponseEntity.success(productDtoList);
    }
}