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

// 该类所属的包名，表明其位于商城API的控制器包下，主要用于处理与用户收藏相关的各种接口请求及对应的业务逻辑，比如获取收藏数据、判断是否收藏、添加或取消收藏等操作。
package com.yami.shop.api.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.bean.app.dto.ProductDto;
import com.yaami.shop.bean.app.dto.UserCollectionDto;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.UserCollection;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.UserCollectionService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import lombok.AllArgsConstructor;
import com.yami.shop.common.response.ServerResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.Objects;

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

    // 通过构造函数注入UserCollectionService实例，用于调用与用户收藏记录相关的业务逻辑方法，比如查询收藏记录、添加或删除收藏记录等操作。
    private final UserCollectionService userCollectionService;

    // 通过构造函数注入ProductService实例，用于调用与商品相关的业务逻辑方法，例如判断商品是否存在、获取收藏商品列表等操作，通常会结合用户收藏记录来实现相关业务功能。
    private final ProductService productService;

    /**
     * 分页返回收藏数据的接口方法。
     * 根据传入的分页参数（page），调用UserCollectionService的getUserCollectionDtoPageByUserId方法，传入当前登录用户的ID（通过SecurityUtils获取）以及分页参数，获取当前用户的分页收藏数据列表，
     * 最后将获取到的分页收藏数据封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param page 分页参数对象，包含页码、每页数量等信息，用于进行分页查询操作，通过该参数可以获取指定页的用户收藏数据列表。
     * @return 返回包含分页用户收藏数据的ServerResponseEntity，成功时其数据部分为IPage<UserCollectionDto>类型，该类型包含了分页后的收藏记录数据以及分页相关的元数据信息（如总页数、总记录数等）。
     */
    @GetMapping("/page")
    @Operation(summary = "分页返回收藏数据", description = "根据用户id获取")
    public ServerResponseEntity<IPage<UserCollectionDto>> getUserCollectionDtoPageByUserId(PageParam page) {
        return ServerResponseEntity.success(userCollectionService.getUserCollectionDtoPageByUserId(page, SecurityUtils.getUser().getUserId()));
    }

    /**
     * 根据商品ID判断该商品是否在收藏夹中的接口方法。
     * 首先，根据传入的商品ID（prodId），通过ProductService的count方法结合LambdaQueryWrapper来查询该商品是否存在（通过判断符合条件的商品记录数量是否小于1来确定），如果不存在则抛出异常。
     * 然后，调用UserCollectionService的count方法结合LambdaQueryWrapper，根据商品ID以及当前登录用户的ID（通过SecurityUtils获取）来查询该用户对该商品的收藏记录数量，
     * 如果数量大于0则表示已收藏，返回表示已收藏的布尔值（true），否则返回表示未收藏的布尔值（false），最后将判断结果封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param prodId 要判断是否被收藏的商品的唯一标识符，通过请求参数传入，用于定位具体的商品记录以及对应的用户收藏记录情况。
     * @return 返回包含表示该商品是否被当前用户收藏的布尔值的ServerResponseEntity，成功时其数据部分为Boolean类型，true表示已收藏，false表示未收藏。
     */
    @GetMapping("isCollection")
    @Operation(summary = "根据商品id获取该商品是否在收藏夹中", description = "传入收藏商品id")
    public ServerResponseEntity<Boolean> isCollection(Long prodId) {
        if (productService.count(new LambdaQueryWrapper<Product>()
               .eq(Product::getProdId, prodId)) < 1) {
            throw new YamiShopBindException("该商品不存在");
        }
        return ServerResponseEntity.success(userCollectionService.count(new LambdaQueryWrapper<UserCollection>()
               .eq(UserCollection::getProdId, prodId)
               .eq(UserCollection::getUserId, SecurityUtils.getUser().getUserId())) > 0);
    }

    /**
     * 添加/取消收藏的接口方法。
     * 根据传入的商品ID（prodId），先判断该商品是否存在（通过ProductService的getProductByProdId方法获取商品对象，若为空则抛出异常），然后获取当前登录用户的ID（通过SecurityUtils获取）。
     * 接着，通过UserCollectionService的count方法结合LambdaQueryWrapper查询该用户对该商品的收藏记录数量，若数量大于0表示已收藏，则调用remove方法结合LambdaQueryWrapper删除对应的收藏记录，实现取消收藏操作；
     * 若数量不大于0表示未收藏，则创建一个新的UserCollection对象，设置创建时间（通过new Date()获取当前时间）、用户ID以及商品ID，然后调用save方法保存该收藏记录，实现添加收藏操作。
     * 最后返回表示操作成功的ServerResponseEntity对象，用于统一的接口响应格式处理，其无具体数据内容（Void类型）。
     *
     * @param prodId 要添加或取消收藏的商品的唯一标识符，通过请求体传入，用于确定具体的商品以及对应的用户收藏操作。
     * @return 返回表示操作成功的ServerResponseEntity，无数据内容（Void类型），用于表示添加或取消收藏操作已成功执行。
     */
    @PostMapping("/addOrCancel")
    @Operation(summary = "添加/取消收藏", description = "传入收藏商品id,如果商品未收藏则收藏商品，已收藏则取消收藏")
    @Parameter(name = "prodId", description = "商品id", required = true)
    public ServerResponseEntity<Void> addOrCancel(@RequestBody Long prodId) {
        if (Objects.isNull(productService.getProductByProdId(prodId))) {
            throw new YamiShopBindException("该商品不存在");
        }
        String userId = SecurityUtils.getUser().getUserId();
        if (userCollectionService.count(new LambdaQueryWrapper<UserCollection>()
               .eq(UserCollection::getProdId, prodId)
               .eq(UserCollection::getUserId, userId)) > 0) {
            userCollectionService.remove(new LambdaQueryWrapper<UserCollection>()
                   .eq(UserCollection::getProdId, prodId)
                   .eq(UserCollection::getUserId, userId));
        } else {
            UserCollection userCollection = new UserCollection();
            userCollection.setCreateTime(new Date());
            userCollection.setUserId(userId);
            userCollection.setProdId(prodId);
            userCollectionService.save(userCollection);
        }
        return ServerResponseEntity.success();
    }

    /**
     * 查询用户收藏商品数量的接口方法。
     * 通过SecurityUtils获取当前登录用户的ID，然后调用UserCollectionService的count方法结合LambdaQueryWrapper，根据用户ID查询该用户的收藏商品记录数量，
     * 最后将查询到的数量封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @return 返回包含用户收藏商品数量的ServerResponseEntity，成功时其数据部分为Long类型，即表示收藏商品的数量。
     */
    /**
     * 查询用户收藏商品数量
     */
    @GetMapping("count")
    @Operation(summary = "查询用户收藏商品数量", description = "查询用户收藏商品数量")
    public ServerResponseEntity<Long> findUserCollectionCount() {
        String userId = SecurityUtils.getUser().getUserId();
        return ServerResponseEntity.success(userCollectionService.count(new LambdaQueryWrapper<UserCollection>().eq(UserCollection::getUserId, userId)));
    }

    /**
     * 获取用户收藏商品列表的接口方法。
     * 根据传入的分页参数（page），调用ProductService的collectionProds方法，传入当前登录用户的ID（通过SecurityUtils获取）以及分页参数，获取当前用户的分页收藏商品列表数据，
     * 最后将获取到的分页收藏商品列表数据封装在ServerResponseEntity中返回，用于统一的接口响应格式处理。
     *
     * @param page 分页参数对象，包含页码、每页数量等信息，用于进行分页查询操作，通过该参数可以获取指定页的用户收藏商品列表数据。
     * @return 返回包含分页用户收藏商品列表数据的ServerResponseEntity，成功时其数据部分为IPage<ProductDto>类型，该类型包含了分页后的收藏商品列表数据以及分页相关的元数据信息（如总页数、总记录数等）。
     */
    @GetMapping("/prods")
    @Operation(summary = "获取用户收藏商品列表", description = "获取用户收藏商品列表")
    public ServerResponseEntity<IPage<ProductDto>> collectionProds(PageParam page) {
        String userId = SecurityUtils.getUser().getUserId();
        IPage<ProductDto> productDtoPage = productService.collectionProds(page, userId);
        return ServerResponseEntity.success(productDtoPage);
    }
}