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

package com.yami.shop.admin.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.bean.enums.AreaLevelEnum;
import com.yami.shop.bean.model.Area;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.service.AreaService;
import org.springframework.beans.factory.annotation.Autowired;
import com.yami.shop.common.response.ServerResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;
import java.util.Objects;

/**
 * AreaController类，用于处理与地区（Area）相关的后台管理接口请求
 * 包含地区信息的分页查询、获取列表、根据父级ID获取列表、获取单个地区信息、保存、修改以及删除等操作
 * @author lgh on 2018/10/26.
 */
@RestController
@RequestMapping("/admin/area")
public class AreaController {

    // 自动注入AreaService，用于调用与地区相关的业务逻辑方法
    @Autowired
    private AreaService areaService;

    /**
     * 分页获取地区信息的接口方法
     * 通过接收Area对象（可能包含查询条件）以及PageParam对象（用于分页参数设置），
     * 调用AreaService的page方法进行分页查询，并返回包含查询结果的ServerResponseEntity对象
     * @param area 可能包含查询条件的地区对象，比如按地区名称等条件查询
     * @param page 分页参数对象，包含页码、每页数量等信息
     * @return 返回包含分页地区信息的ServerResponseEntity，成功时其数据部分为IPage<Area>类型
     */
    @GetMapping("/page")
    @PreAuthorize("@pms.hasPermission('admin:area:page')")
    public ServerResponseEntity<IPage<Area>> page(Area area, PageParam<Area> page) {
        IPage<Area> sysUserPage = areaService.page(page, new LambdaQueryWrapper<Area>());
        return ServerResponseEntity.success(sysUserPage);
    }

    /**
     * 获取省市地区信息的接口方法
     * 根据传入的Area对象（可能包含地区名称等模糊查询条件），
     * 调用AreaService的list方法，使用LambdaQueryWrapper进行条件查询，获取符合条件的地区列表，
     * 最后返回包含地区列表信息的ServerResponseEntity对象
     * @param area 可能包含查询条件的地区对象，如按地区名称模糊查询
     * @return 返回包含查询到的地区列表信息的ServerResponseEntity，成功时其数据部分为List<Area>类型
     */
    @GetMapping("/list")
    @PreAuthorize("@pms.hasPermission('admin:area:list')")
    public ServerResponseEntity<List<Area>> list(Area area) {
        List<Area> areas = areaService.list(new LambdaQueryWrapper<Area>()
               .like(area.getAreaName()!= null, Area::getAreaName, area.getAreaName()));
        return ServerResponseEntity.success(areas);
    }

    /**
     * 通过父级id获取区域列表的接口方法
     * 直接调用AreaService的listByPid方法，传入父级ID，获取对应父级下的区域列表，
     * 然后返回包含该区域列表信息的ServerResponseEntity对象
     * @param pid 父级地区的ID
     * @return 返回包含对应父级下区域列表信息的ServerResponseEntity，成功时其数据部分为List<Area>类型
     */
    @GetMapping("/listByPid")
    public ServerResponseEntity<List<Area>> listByPid(Long pid) {
        List<Area> list = areaService.listByPid(pid);
        return ServerResponseEntity.success(list);
    }

    /**
     * 获取指定ID地区详细信息的接口方法
     * 通过路径变量获取地区的ID，调用AreaService的getById方法获取对应的地区对象，
     * 最后返回包含该地区对象信息的ServerResponseEntity对象
     * @param id 要获取信息的地区的ID
     * @return 返回包含指定地区详细信息的ServerResponseEntity，成功时其数据部分为Area类型
     */
    @GetMapping("/info/{id}")
    @PreAuthorize("@pms.hasPermission('admin:area:info')")
    public ServerResponseEntity<Area> info(@PathVariable("id") Long id) {
        Area area = areaService.getById(id);
        return ServerResponseEntity.success(area);
    }

    /**
     * 保存地区信息的接口方法
     * 首先判断传入的地区对象是否有父级ID，如果有，则根据父级地区的级别来设置当前地区的级别，
     * 同时调用AreaService的removeAreaCacheByParentId方法清除对应父级ID的地区缓存，
     * 最后调用AreaService的save方法保存地区信息，并返回表示成功的ServerResponseEntity对象
     * @param area 要保存的地区对象，通过请求体传入，且经过了数据校验（@Valid注解）
     * @return 返回表示保存成功的ServerResponseEntity，无数据内容（Void类型）
     */
    @PostMapping
    @PreAuthorize("@pms.hasPermission('admin:area:save')")
    public ServerResponseEntity<Void> save(@Valid @RequestBody Area area) {
        if (area.getParentId()!= null) {
            Area parentArea = areaService.getById(area.getParentId());
            area.setLevel(parentArea.getLevel() + 1);
            areaService.removeAreaCacheByParentId(area.getParentId());
        }
        areaService.save(area);
        return ServerResponseEntity.success();
    }

    /**
     * 修改地区信息的接口方法
     * 先根据传入地区对象的ID获取数据库中已存在的对应地区对象（areaDb），
     * 然后判断当前地区的级别是否允许修改（一级、二级行政地区有相应限制），如果不允许则抛出异常，
     * 接着调用hasSameName方法检查地区名称是否重复，
     * 最后调用AreaService的updateById方法更新地区信息，并清除对应父级ID的地区缓存，返回表示成功的ServerResponseEntity对象
     * @param area 要修改的地区对象，通过请求体传入，且经过了数据校验（@Valid注解）
     * @return 返回表示修改成功的ServerResponseEntity，无数据内容（Void类型）
     */
    @PutMapping
    @PreAuthorize("@pms.hasPermission('admin:area:update')")
    public ServerResponseEntity<Void> update(@Valid @RequestBody Area area) {
        Area areaDb = areaService.getById(area.getAreaId());
        // 判断当前省市区级别，如果是1级、2级则不能修改级别，不能修改成别人的下级
        if (Objects.equals(areaDb.getLevel(), AreaLevelEnum.FIRST_LEVEL.value()) &&!Objects.equals(area.getLevel(), AreaLevelEnum.FIRST_LEVEL.value())) {
            throw new YamiShopBindException("不能改变一级行政地区的级别");
        }
        if (Objects.equals(areaDb.getLevel(), AreaLevelEnum.SECOND_LEVEL.value()) &&!Objects.equals(area.getLevel(), AreaLevelEnum.SECOND_LEVEL.value())) {
            throw new YamiShopBindException("不能改变二级行政地区的级别");
        }
        hasSameName(area);
        areaService.updateById(area);
        areaService.removeAreaCacheByParentId(area.getParentId());
        return ServerResponseEntity.success();
    }

    /**
     * 删除地区信息的接口方法
     * 根据路径变量获取要删除地区的ID，先调用AreaService的getById方法获取对应的地区对象，
     * 然后调用AreaService的removeById方法删除地区信息，同时清除对应父级ID的地区缓存，
     * 最后返回表示成功的ServerResponseEntity对象
     * @param id 要删除的地区的ID
     * @return 返回表示删除成功的ServerResponseEntity，无数据内容（Void类型）
     */
    @DeleteMapping("/{id}")
    @PreAuthorize("@pms.hasPermission('admin:area:delete')")
    public ServerResponseEntity<Void> delete(@PathVariable Long id) {
        Area area = areaService.getById(id);
        areaService.removeById(id);
        areaService.removeAreaCacheByParentId(area.getParentId());
        return ServerResponseEntity.success();
    }

    /**
     * 私有方法，用于检查要保存或修改的地区名称是否已存在（在同一父级下）
     * 通过构建LambdaQueryWrapper，设置查询条件（父级ID相同、地区名称相同、排除自身ID等），
     * 调用AreaService的count方法统计符合条件的记录数量，如果数量大于0则表示名称已存在，抛出异常
     * @param area 要检查名称是否重复的地区对象
     */
    private void hasSameName(Area area) {
        long count = areaService.count(new LambdaQueryWrapper<Area>()
               .eq(Area::getParentId, area.getParentId())
               .eq(Area::getAreaName, area.getAreaName())
               .ne(Objects.nonNull(area.getAreaId()) &&!Objects.equals(area.getAreaId(), 0L), Area::getAreaId, area.getAreaId())
        );
        if (count > 0) {
            throw new YamiShopBindException("该地区已存在");
        }
    }
}