package com.gxwebsoft.common.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.*;
import com.gxwebsoft.common.system.service.*;
import com.gxwebsoft.common.system.param.TenantParam;
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 io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 租户控制器
 *
 * @author 科技小王子
 * @since 2023-07-17 17:49:53
 */
@Tag(name = "系统租户")
@RestController
@RequestMapping("/api/system/tenant")
public class TenantController extends BaseController {
  @Resource
  private TenantService tenantService;
  @Resource
  private MenuService menuService;
  @Resource
  private RoleMenuService roleMenuService;
  @Resource
  private CompanyService companyService;
  @Resource
  private RedisUtil redisUtil;
  @Resource
  private UserService userService;
  // cms权限参考租户, 默认取平台租户
  @Value("${websoft.cms.ref-tenant-id:10257}")
  private Integer cmsRefTenantId;

  @Operation(summary = "分页查询租户")
  @GetMapping("/page")
  public ApiResult<PageResult<Tenant>> page(TenantParam param) {
    // 如果传了 all=true，查询全部租户；否则自动用当前登录用户的 userId
    if (param.getAll() == null || !param.getAll()) {
      if (param.getUserId() == null) {
        final User loginUser = getLoginUser();
        if (loginUser != null && loginUser.getUserId() != null) {
          param.setUserId(loginUser.getUserId());
        }
      }
    }
    PageResult<Tenant> result = tenantService.pageRel(param);
    // 如果传入 mask=false，设置不脱敏
    if (param.getMask() != null && !param.getMask()) {
      if (result.getList() != null) {
        for (Tenant tenant : result.getList()) {
          tenant.setPhoneMasked(false);
        }
      }
    }
    return success(result);
  }

  @PreAuthorize("hasAuthority('sys:tenant:list')")
  @Operation(summary = "查询全部租户")
  @GetMapping()
  public ApiResult<List<Tenant>> list(TenantParam param) {
    // 使用关联查询
    return success(tenantService.listRel(param));
  }

  @Operation(summary = "根据id查询租户")
  @GetMapping("/{id}")
  public ApiResult<Tenant> get(@PathVariable("id") Integer id) {
    Tenant tenant = tenantService.getById(id);
    // 附加企业信息
    List<Company> list = companyService.list(new LambdaQueryWrapper<Company>().eq(Company::getTenantId, tenant.getTenantId()).eq(Company::getAuthoritative, true));
    if (!CollectionUtils.isEmpty(list)) {
      final Company company = list.get(0);
      tenant.setCompany(company);
    }
    return success(tenant);
  }

  @Operation(summary = "根据code搜索租户")
  @GetMapping("/getTenantId/{code}")
  public ApiResult<Integer> getTenantIdByKeywords(@PathVariable("code") String code) {
    String key = "TenantCode:".concat(code);
    // 查询缓存
    final String string = redisUtil.get(key);
    if(string != null){
      return success(JSONUtil.parseObject(string, Integer.class));
    }
    // 使用关联查询
    final Tenant tenant = tenantService.getOne(new LambdaUpdateWrapper<Tenant>().eq(Tenant::getTenantId, code).or().eq(Tenant::getTenantCode, code).last("limit 1"));
    if(tenant == null){
      return fail("应用不存在或已过期",null);
    }
    redisUtil.set(key,tenant.getTenantId().toString(),1L, TimeUnit.DAYS);
    return success(tenant.getTenantId());
  }

  @Operation(summary = "根据code搜索租户")
  @GetMapping("/getByCode/{code}")
  public ApiResult<Tenant> getByCode(@PathVariable("code") String code) {
    return success(tenantService.getByCodeRel(code));
  }

  @PreAuthorize("hasAuthority('sys:tenant:save')")
  @OperationLog
  @Operation(summary = "添加租户")
  @PostMapping()
  public ApiResult<?> save(@RequestBody Tenant tenant) {
    if (tenantService.save(tenant)) {
      return success("添加成功");
    }
    return fail("添加失败");
  }

  @PreAuthorize("hasAuthority('sys:tenant:update')")
  @OperationLog
  @Operation(summary = "修改租户")
  @PutMapping()
  public ApiResult<?> update(@RequestBody Tenant tenant) {
    final User loginUser = getLoginUser();
    if(loginUser != null){
      tenant.setTenantId(loginUser.getTenantId());
    }
    if (tenantService.updateById(tenant)) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

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

  @PreAuthorize("hasAuthority('sys:tenant:save')")
  @OperationLog
  @Operation(summary = "批量添加租户")
  @PostMapping("/batch")
  public ApiResult<?> saveBatch(@RequestBody List<Tenant> list) {
    if (tenantService.saveBatch(list)) {
      return success("添加成功");
    }
    return fail("添加失败");
  }

  @PreAuthorize("hasAuthority('sys:tenant:update')")
  @OperationLog
  @Operation(summary = "批量修改租户")
  @PutMapping("/batch")
  public ApiResult<?> removeBatch(@RequestBody BatchParam<Tenant> batchParam) {
    if (batchParam.update(tenantService, "tenant_id")) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

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

  @Operation(summary = "租户角色权限初始化")
  @GetMapping("/role-menu/{id}")
  public ApiResult<List<Menu>> initialization(@PathVariable("id") Integer roleId) {
    List<Menu> menus = menuService.list(new LambdaQueryWrapper<Menu>().orderByAsc(Menu::getSortNumber));
    List<RoleMenu> roleMenus = roleMenuService.list(new LambdaQueryWrapper<RoleMenu>()
      .eq(RoleMenu::getRoleId, roleId));
    for (Menu menu : menus) {
      menu.setChecked(roleMenus.stream().anyMatch((d) -> d.getMenuId().equals(menu.getMenuId())));
    }
    List<Integer> menuIds = menus.stream().map(Menu::getMenuId).collect(Collectors.toList());
    roleMenuService.remove(new LambdaUpdateWrapper<RoleMenu>().eq(RoleMenu::getRoleId, roleId));
    if (menuIds.size() > 0) {
      List<RoleMenu> roleMenuList = new ArrayList<>();
      for (Integer menuId : menuIds) {
        RoleMenu roleMenu = new RoleMenu();
        roleMenu.setRoleId(roleId);
        roleMenu.setMenuId(menuId);
        roleMenuList.add(roleMenu);
      }
      if (!roleMenuService.saveBatch(roleMenuList)) {
        throw new BusinessException("保存失败");
      }
    }
    return success(menus);
  }

  @OperationLog
  @Operation(summary = "授予当前租户cms建站权限")
  @PostMapping("/grantCmsPermission")
  public ApiResult<?> grantCmsPermission(@RequestBody(required = false) Map<String, Object> body) {
    final Integer curTenant = getTenantId();
    if (curTenant == null) {
      return fail("获取当前租户失败, 请重新登录");
    }
    // 参考租户优先级: 请求参数 > 企业当前使用的租户模板 > 配置项websoft.cms.ref-tenant-id
    Integer refTenant = null;
    final Object refTenantId = body == null ? null : body.get("refTenantId");
    if (refTenantId instanceof Number) {
      refTenant = ((Number) refTenantId).intValue();
    } else if (refTenantId != null && refTenantId.toString().matches("\\d+")) {
      refTenant = Integer.valueOf(refTenantId.toString());
    }
    if (refTenant == null) {
      final Company company = getCompany();
      if (company != null && company.getPlanId() != null) {
        refTenant = company.getPlanId();
      }
    }
    if (refTenant == null) {
      refTenant = cmsRefTenantId;
    }
    if (refTenant == null) {
      return fail("未找到参考租户, 请配置websoft.cms.ref-tenant-id");
    }
    if (refTenant.equals(curTenant)) {
      return fail("参考租户不能与当前租户相同");
    }
    return tenantService.grantCmsPermission(refTenant, curTenant);
  }

  @Operation(summary = "创建租户")
  @PostMapping("/saveByPhone")
  public ApiResult<?> saveByPhone(@RequestBody Tenant tenant) {
    final String phone = tenant.getPhone();
    if(tenant.getTenantName() == null){
      return null;
    }
    if(tenant.getTenantCode() == null){
      return null;
    }
    if (tenantService.count(new LambdaQueryWrapper<Tenant>().eq(Tenant::getTenantCode, phone)) > 0) {
      return null;
    }
    if (tenantService.save(tenant)) {
      // 租户初始化
      final Company company = new Company();
      company.setDomain(tenant.getTenantId().toString().concat(".websoft.top"));
      company.setPhone(phone);
      company.setEmail(null);
      company.setPassword(userService.encodePassword(phone));
      company.setTid(tenant.getTenantId());
      company.setCompanyName(tenant.getTenantName());
      company.setShortName(tenant.getTenantName());
      company.setTenantId(tenant.getTenantId());
      tenantService.initialization(company);
      return success("创建成功",tenant);
    }
    return null;
  }
}
