package com.gxwebsoft.project.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.cms.entity.CmsWebsite;
import com.gxwebsoft.cms.param.CmsWebsiteParam;
import com.gxwebsoft.cms.service.CmsWebsiteService;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Role;
import com.gxwebsoft.project.entity.ProjectUser;
import com.gxwebsoft.project.service.ProjectService;
import com.gxwebsoft.project.entity.Project;
import com.gxwebsoft.project.param.ProjectParam;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.project.service.ProjectUserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 应用控制器
 *
 * @author 科技小王子
 * @since 2025-03-14 16:21:11
 */
@Tag(name = "应用管理")
@RestController
@RequestMapping("/api/project/project")
public class ProjectController extends BaseController {
  @Resource
  private ProjectService projectService;
  @Resource
  private ProjectUserService projectUserService;
  @Resource
  private CmsWebsiteService cmsWebsiteService;

  @PreAuthorize("hasAuthority('project:project:list')")
  @Operation(summary = "分页查询应用")
  @GetMapping("/page")
  public ApiResult<PageResult<Project>> page(ProjectParam param) {
    final User loginUser = getLoginUser();
    if (loginUser != null) {
      param.setLoginUserId(loginUser.getUserId());
      final List<Role> roles = loginUser.getRoles();
      if (!CommonUtil.hasRole(roles, "admin") && !CommonUtil.hasRole(roles, "superAdmin")) {
        final List<ProjectUser> projectUsers = projectUserService.list(new LambdaQueryWrapper<ProjectUser>().eq(ProjectUser::getUserId, loginUser.getUserId()));
        final Set<Integer> appIds = projectUsers.stream().map(ProjectUser::getAppId).collect(Collectors.toSet());
        param.setAppIds(appIds);
      }
      final PageResult<Project> result = projectService.pageRel(param);
      final CmsWebsiteParam websiteParam = new CmsWebsiteParam();
      final List<Project> projects = result.getList();
      if(!CollectionUtils.isEmpty(projects)){
        final Set<Integer> collectByProject = projects.stream().map(Project::getWebsiteId).collect(Collectors.toSet());
        websiteParam.setWebsiteIds(collectByProject);
        final PageResult<CmsWebsite> websitePageResult = cmsWebsiteService.pageRelAll(websiteParam);
        if (!CollectionUtils.isEmpty(websitePageResult.getList())) {
          final Map<Integer, List<CmsWebsite>> collectByWebsite = websitePageResult.getList().stream().collect(Collectors.groupingBy(CmsWebsite::getWebsiteId));
          result.getList().forEach(item -> {
            final List<CmsWebsite> cmsWebsites = collectByWebsite.get(item.getWebsiteId());
            if (!CollectionUtils.isEmpty(cmsWebsites)) {
              final CmsWebsite website = cmsWebsites.get(0);
              item.setAppUrl(website.getDomain());
              item.setAdminUrl(website.getAdminUrl());
              item.setAppIcon(website.getWebsiteLogo());
              item.setAppType(website.getWebsiteType());
              item.setSuperAdminPhone(website.getSuperAdminPhone());
            }
          });
        }
      }
      return success(result);
    }
    return fail("获取失败",null);
  }

  @PreAuthorize("hasAuthority('project:project:list')")
  @Operation(summary = "查询全部应用")
  @GetMapping()
  public ApiResult<List<Project>> list(ProjectParam param) {
    // 使用关联查询
    return success(projectService.listRel(param));
  }

  @PreAuthorize("hasAuthority('project:project:list')")
  @Operation(summary = "根据id查询应用")
  @GetMapping("/{id}")
  public ApiResult<Project> get(@PathVariable("id") Integer id) {
    // 使用关联查询
    return success(projectService.getByIdRel(id));
  }

  @PreAuthorize("hasAuthority('project:project:save')")
  @OperationLog
  @Operation(summary = "添加应用")
  @PostMapping()
  public ApiResult<?> save(@RequestBody Project project) {
    // 记录当前登录用户id
    User loginUser = getLoginUser();
    if (loginUser != null) {
      project.setUserId(loginUser.getUserId());
      final Project one = projectService.getOne(new LambdaQueryWrapper<Project>().eq(Project::getAppCode, project.getAppCode()).last("limit 1"));
      if (!ObjectUtil.isEmpty(one)) {
        return fail("应用标识已存在");
      }
      if (projectService.save(project)) {
        final ProjectUser user = new ProjectUser();
        user.setUserId(loginUser.getUserId());
        user.setAppId(project.getAppId());
        user.setRole(30);
        user.setNickname(loginUser.getNickname());
        projectUserService.save(user);
        return success("添加成功");
      }
    }
    return fail("添加失败");
  }

  @PreAuthorize("hasAuthority('project:project:update')")
  @OperationLog
  @Operation(summary = "修改应用")
  @PutMapping()
  public ApiResult<?> update(@RequestBody Project project) {
    if(project.getAppStatus() != null && project.getAppStatus().equals("已上架")){
      project.setProgress(100);
    }
    if (projectService.updateById(project)) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

  @PreAuthorize("hasAuthority('project:project:remove')")
  @OperationLog
  @Operation(summary = "删除应用")
  @DeleteMapping("/{id}")
  public ApiResult<?> remove(@PathVariable("id") Integer id) {
    if (projectService.removeById(id)) {
      return success("删除成功");
    }
    return fail("删除失败");
  }

  @PreAuthorize("hasAuthority('project:project:save')")
  @OperationLog
  @Operation(summary = "批量添加应用")
  @PostMapping("/batch")
  public ApiResult<?> saveBatch(@RequestBody List<Project> list) {
    if (projectService.saveBatch(list)) {
      return success("添加成功");
    }
    return fail("添加失败");
  }

  @PreAuthorize("hasAuthority('project:project:update')")
  @OperationLog
  @Operation(summary = "批量修改应用")
  @PutMapping("/batch")
  public ApiResult<?> removeBatch(@RequestBody BatchParam<Project> batchParam) {
    if (batchParam.update(projectService, "app_id")) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

  @PreAuthorize("hasAuthority('project:project:remove')")
  @OperationLog
  @Operation(summary = "批量删除应用")
  @DeleteMapping("/batch")
  public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
    if (projectService.removeByIds(ids)) {
      return success("删除成功");
    }
    return fail("删除失败");
  }


  @Operation(summary = "统计信息")
  @GetMapping("/data")
  public ApiResult<Map<String, Integer>> data() {
    Map<String, Integer> data = new HashMap<>();
    final LambdaQueryWrapper<Project> wrapper = new LambdaQueryWrapper<>();
    final User loginUser = getLoginUser();
    if(loginUser != null){

      final List<Role> roles = loginUser.getRoles();
      if (!CommonUtil.hasRole(roles, "admin") && !CommonUtil.hasRole(roles, "superAdmin")) {
        final List<ProjectUser> projectUsers = projectUserService.list(new LambdaQueryWrapper<ProjectUser>().eq(ProjectUser::getUserId, loginUser.getUserId()));
        final Set<Integer> userIds = projectUsers.stream().map(ProjectUser::getAppId).collect(Collectors.toSet());
        wrapper.in(Project::getUserId,userIds);
      }

      Integer totalNum = Math.toIntExact(projectService.count(wrapper));

      wrapper.eq(Project::getAppStatus, "开发中");
      Integer totalNum2 = Math.toIntExact(projectService.count(wrapper));

      wrapper.clear();
      wrapper.eq(Project::getAppStatus,"已上架");
      Integer totalNum3 = Math.toIntExact(projectService.count(wrapper));

      wrapper.clear();
      wrapper.eq(Project::getAppStatus,"已上架").eq(Project::getShowExpiration,true);
      Integer totalNum4 = Math.toIntExact(projectService.count(wrapper));

      wrapper.clear();
      wrapper.eq(Project::getAppStatus, "已下架");
      Integer totalNum5 = Math.toIntExact(projectService.count(wrapper));

      wrapper.clear();
      wrapper.eq(Project::getShowCase,true);
      Integer totalNum6 = Math.toIntExact(projectService.count(wrapper));

      wrapper.clear();
      wrapper.eq(Project::getShowIndex,true);
      Integer totalNum7 = Math.toIntExact(projectService.count(wrapper));

      data.put("totalNum", totalNum);
      data.put("totalNum2", totalNum2);
      data.put("totalNum3", totalNum3);
      data.put("totalNum4", totalNum4);
      data.put("totalNum5", totalNum5);
      data.put("totalNum6", totalNum6);
      data.put("totalNum7", totalNum7);
    }
    return success(data);
  }

  @Operation(summary = "统计信息")
  @GetMapping("/count")
  public ApiResult<Map<String, BigDecimal>> count() {
    Map<String, BigDecimal> data = new HashMap<>();
    final User loginUser = getLoginUser();
    if (loginUser == null) {
      return fail("请先登录", null);
    }

    // 今天日期
    DateTime date = DateUtil.date();
    // 获取当前年份的起止时间
    LocalDateTime startOfYear = LocalDateTime.now().withMonth(1).withDayOfMonth(1)
      .withHour(0).withMinute(0).withSecond(0);
    LocalDateTime endOfYear = startOfYear.plusYears(1).minusNanos(1);
    // 去年的起止时间
    LocalDateTime startOfLastYear = LocalDateTime.now().minusYears(1).withMonth(1).withDayOfMonth(1)
      .withHour(0).withMinute(0).withSecond(0);
    LocalDateTime endOfLastYear = startOfLastYear.plusYears(1).minusNanos(1);

    // TODO 近30天可催收的续费总额
    // 下个月的今天
    final DateTime nextMonth = DateUtil.nextMonth();
    final BigDecimal totalPrice30 = projectService.sumMoney(new LambdaQueryWrapper<Project>()
      .lt(Project::getExpirationTime, nextMonth)
      .gt(Project::getExpirationTime, date)
      .eq(Project::getDeleted, 0)
    );
    data.put("totalPrice30", totalPrice30);


    // TODO 今年已收续费总额
    BigDecimal yearTotalPrice = projectService.sumMoney(new LambdaQueryWrapper<Project>()
      .between(Project::getUpdateTime, startOfYear, endOfYear)
      .eq(Project::getDeleted, 0)
    );
    data.put("yearTotalPrice", yearTotalPrice);

    // TODO 去年已收续费总额
    BigDecimal lastTotalPrice = projectService.sumMoney(new LambdaQueryWrapper<Project>()
      .between(Project::getUpdateTime, startOfLastYear, endOfLastYear)
      .eq(Project::getDeleted, 0)
      .eq(Project::getDeleted,0)
      );
    // 去年已收续费总额
    data.put("lastTotalPrice", lastTotalPrice);

    return success(data);
  }

}
