package com.cf.imes.module.system.controller.admin.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.validation.Mobile;
import com.cf.imes.framework.ip.core.service.IPQueryService;
import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
import com.cf.imes.framework.operatelog.core.annotations.OperateLog;
import com.cf.imes.framework.security.config.SecurityProperties;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthAppTokenReqVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginSmsCheckReqVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthSmsSendReqVO;
import com.cf.imes.module.system.convert.auth.AuthConvert;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import com.cf.imes.module.system.enums.logger.LoginLogTypeEnum;
import com.cf.imes.module.system.service.auth.AdminAuthService;
import com.cf.imes.module.system.service.organ.OrganService;
import com.cf.imes.module.system.service.permission.MenuService;
import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.permission.RoleService;
import com.cf.imes.module.system.service.sms.SmsCodeService;
import com.cf.imes.module.system.service.tokenconfig.TokenConfigService;
import com.cf.imes.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.cf.imes.framework.common.pojo.CommonResult.success;
import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet;
import static com.cf.imes.framework.common.util.servlet.ServletUtils.getClientIP;

@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {

    @Resource
    private AdminAuthService authService;
    @Resource
    private AdminUserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private PermissionService permissionService;

    @Resource
    private SecurityProperties securityProperties;

    @Resource
    private SmsCodeService smsCodeService;

    @Resource
    private OrganService organService;

    @Resource
    private IPQueryService ipQueryService;

    @Resource
    private TokenConfigService tokenConfigService;

    @PostMapping("/manage/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> manageEndPointlogin(@Valid @RequestBody AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO, true));
    }

    @PostMapping("/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> login(@Valid @RequestBody AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO, false));
    }

    @GetMapping("/login/check")
    @PermitAll
    @Operation(summary = "校验账号")
    @OperateLog(enable = false)
    @Parameter(name = "mobile", description = "手机号", required = true)
    public CommonResult<Boolean> loginCheck(
            @Param("mobile") @NotEmpty(message = "请输入手机号") @Mobile(message = "账号密码不正确，请重新输入", ignoreWhenCheck = {"admin"}) String mobile) {
        return success(authService.loginCheck(mobile));
    }

    @PostMapping("/login/sms/check")
    @PermitAll
    @Operation(summary = "校验登录验证码")
    @OperateLog(enable = false)
    public CommonResult<Boolean> loginSmsCheck(@Valid @RequestBody AuthLoginSmsCheckReqVO reqVO) {
        return success(authService.loginSmsCheck(reqVO));
    }

    /**
     * 根据应用 Token 获取所属组织编号，供外部应用在未登录场景下识别组织。
     *
     * @param reqVO 应用 Token 请求参数
     * @return 组织编号
     */
    @PostMapping("/app-token/organ-id")
    @PermitAll
    @Operation(summary = "根据应用 Token 获取组织编号")
    @OperateLog(enable = false)
    public CommonResult<Long> getOrganIdByAppToken(@Valid @RequestBody AuthAppTokenReqVO reqVO) {
        return success(tokenConfigService.getOrganIdByAppToken(reqVO.getAppToken()));
    }

    @PostMapping("/logout")
    @PermitAll
    @Operation(summary = "登出系统")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> logout(HttpServletRequest request) {
        String token = SecurityFrameworkUtils.obtainAuthorization(request,
                securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
        if (StringUtils.isNotBlank(token)) {
            authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
        }
        return success(true);
    }

    @GetMapping("/get-permission-info")
    @Operation(summary = "获取登录用户的权限信息")
    public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo(HttpServletRequest request) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (ObjectUtil.isNull(loginUser)) {
            throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED);
        }
        Long userId = loginUser.getId();
        // 1.1 获得用户信息
        AdminUserDO user = userService.getUser(userId);
        if (user == null) {
            return success(null);
        }
        // 获取机构的有效期
        OrganizationDO organizationDO = organService.validOrgan(user.getOrganId());
        IPQueryDataRespDTO ipQueryDataRespDTO = null;
        if (ipQueryService.serviceEnable()) {
            // 从ip获取地域信息
            ipQueryDataRespDTO = ipQueryService.querySource(getClientIP(request));
        }

        // 1.2 获得角色列表
        Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(userId);
        if (CollUtil.isEmpty(roleIds)) {
            return success(AuthConvert.INSTANCE.convert(user, organizationDO, ipQueryDataRespDTO, Collections.emptyList(), Collections.emptyList()));
        }
        List<RoleDO> roles = roleService.getRoleList1(roleIds);
        roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色

        // 1.3 获得菜单列表
        Set<Long> menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId());
        List<MenuDO> menuList = new ArrayList<>();
        if (CollUtil.isNotEmpty(menuIds)) {
            if (SecurityFrameworkUtils.isManageEndPoint()) {
                menuList = menuService.getManageEndPointMenuList(menuIds);
            } else {
                menuList = menuService.getCustomEndPointMenuList(menuIds);
            }
        }
        menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单

        // 2. 拼接结果返回
        return success(AuthConvert.INSTANCE.convert(user, organizationDO, ipQueryDataRespDTO, roles, menuList));
    }

    // ========== 短信登录相关 ==========

    @PostMapping("/send-sms-code")
    @PermitAll
    @Operation(summary = "发送手机验证码")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
        authService.sendSmsCode(reqVO);
        return success(true);
    }

    @PutMapping("/sms-code")
    @Operation(summary = "发送短信验证码")
    @PermitAll
    @OperateLog(enable = false)
    public CommonResult<Boolean> sendSmsCode(@Valid @RequestBody SmsCodeSendReqDTO reqDTO) {
        // 获取请求ip
        reqDTO.setCreateIp(getClientIP());
        // 发送验证码
        smsCodeService.sendSmsCode(reqDTO);
        return success(true);
    }

    @GetMapping("/mes/token")
    @Operation(summary = "创建mes系统jwt token")
    public CommonResult<String> getMesJwtToken() {
        return success(authService.getMesJwtToken());
    }
}
