package com.multictrl.modules.security.controller;

import com.multictrl.common.exception.ErrorCode;
import com.multictrl.common.exception.RenException;
import com.multictrl.common.utils.IpUtils;
import com.multictrl.common.utils.Result;
import com.multictrl.common.validator.AssertUtils;
import com.multictrl.common.validator.ValidatorUtils;
import com.multictrl.modules.business.dto.DockDTO;
import com.multictrl.modules.business.service.DockService;
import com.multictrl.modules.log.entity.SysLogLoginEntity;
import com.multictrl.modules.log.enums.LoginOperationEnum;
import com.multictrl.modules.log.enums.LoginStatusEnum;
import com.multictrl.modules.log.service.SysLogLoginService;
import com.multictrl.modules.security.dto.LoginDTO;
import com.multictrl.modules.security.dto.MqttAuthDTO;
import com.multictrl.modules.security.dto.MqttAuthVO;
import com.multictrl.modules.security.password.PasswordUtils;
import com.multictrl.modules.security.service.CaptchaService;
import com.multictrl.modules.security.service.SysUserTokenService;
import com.multictrl.modules.security.user.SecurityUser;
import com.multictrl.modules.security.user.UserDetail;
import com.multictrl.modules.sys.dto.SysUserDTO;
import com.multictrl.modules.sys.enums.SuperAdminEnum;
import com.multictrl.modules.sys.enums.UserStatusEnum;
import com.multictrl.modules.sys.service.SysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 登录
 *
 * @author Sdy
 */
@RestController
@Tag(name = "登录管理")
@RequiredArgsConstructor
public class LoginController {
    private final SysUserService sysUserService;
    private final SysUserTokenService sysUserTokenService;
    private final CaptchaService captchaService;
    private final SysLogLoginService sysLogLoginService;
    private final DockService dockService;


    @GetMapping("captcha")
    @Operation(summary = "验证码")
    @Parameter(in = ParameterIn.QUERY, ref = "string", name = "uuid", required = true)
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        //uuid不能为空
        AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);

        //生成验证码
        captchaService.create(response, uuid);
    }

    @PostMapping("login")
    @Operation(summary = "登录")
    public Result<Object> login(HttpServletRequest request, @RequestBody LoginDTO login) {
        //效验数据
        ValidatorUtils.validateEntity(login);

        //验证码是否正确
        boolean flag = captchaService.validate(login.getUuid(), login.getCaptcha());
        if (!flag) {
            return new Result<Object>().error(ErrorCode.CAPTCHA_ERROR);
        }

        //用户信息
        SysUserDTO user = sysUserService.getByUsername(login.getUsername());

        SysLogLoginEntity log = new SysLogLoginEntity();
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));

        //用户不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(login.getUsername());
            sysLogLoginService.save(log);

            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //密码错误
        if (!PasswordUtils.matches(login.getPassword(), user.getPassword())) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }

        //账号停用
        if (user.getStatus() == UserStatusEnum.DISABLE.value()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new RenException(ErrorCode.ACCOUNT_DISABLE);
        }

        //登录成功
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        sysLogLoginService.save(log);

        return sysUserTokenService.createToken(user.getId());
    }

    @PostMapping("logout")
    @Operation(summary = "退出")
    public Result<Object> logout(HttpServletRequest request) {
        UserDetail user = SecurityUser.getUser();

        //退出
        sysUserTokenService.logout(user.getId());

        //用户信息
        SysLogLoginEntity log = new SysLogLoginEntity();
        log.setOperation(LoginOperationEnum.LOGOUT.value());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setIp(IpUtils.getIpAddr(request));
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        log.setCreateDate(new Date());
        sysLogLoginService.save(log);

        return new Result<Object>();
    }

    @PostMapping("/mqtt/auth")
    @Operation(summary = "mqtt认证", hidden = true)
    public MqttAuthVO mqttAuth(@RequestBody MqttAuthDTO login) {
        if (login.getUsername() == null || login.getPassword() == null) {
            return new MqttAuthVO().setResult("deny");
        }

        //给机场配置专属用户名密码
        if (login.getUsername().equals("dock") && login.getPassword().equals("Dock@2023")) {
            return new MqttAuthVO().setResult("allow").setIs_superuser(true).setAcl(new ArrayList<>());
        }

        //用户、账号、密码校验
        SysUserDTO user = sysUserService.getByUsername(login.getUsername());
        if (user == null || user.getStatus() == UserStatusEnum.DISABLE.value() ||
                (!PasswordUtils.matches(login.getPassword(), user.getPassword()) && !login.getPassword().equals(user.getPassword()))
        ) {
            return new MqttAuthVO().setResult("deny");
        }

        //分配权限
        if (SuperAdminEnum.YES.value() == user.getSuperAdmin()) {
            return new MqttAuthVO().setResult("allow").setIs_superuser(true).setAcl(new ArrayList<>());
        } else {
            String topic = "thing/product/%s/#";
            List<MqttAuthVO.Acl> aclList = new ArrayList<>();
            List<DockDTO> dockList = dockService.getUserDockList(user.getId());
            for (DockDTO dto : dockList) {
                MqttAuthVO.Acl acl = new MqttAuthVO.Acl();
                acl.setAction("publish");
                acl.setPermission("allow");
                acl.setTopic(topic.formatted(dto.getDockSn()));
                aclList.add(acl);

                MqttAuthVO.Acl acl2 = new MqttAuthVO.Acl();
                acl2.setAction("subscribe");
                acl2.setPermission("allow");
                acl2.setTopic(topic.formatted(dto.getDockSn()));
                aclList.add(acl2);
            }
            aclList.add(new MqttAuthVO.Acl().setAction("publish").setPermission("deny").setTopic("#"));
            aclList.add(new MqttAuthVO.Acl().setAction("subscribe").setPermission("deny").setTopic("#"));
            return new MqttAuthVO().setResult("allow").setIs_superuser(false).setAcl(aclList);
        }
    }

}
