package org.dromara.auth.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.auth.domain.vo.LoginVo;
import org.dromara.auth.service.IAuthStrategy;
import org.dromara.auth.service.SysLoginService;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginBody;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sms.client.SmsSendTestClient;
import org.dromara.resource.api.RemoteMessageService;
import org.dromara.system.api.RemoteClientService;
import org.dromara.system.api.RemoteTenantService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.dromara.system.api.domain.vo.RemoteTenantVo;
import org.dromara.system.api.domain.vo.RemoteUserVo;
import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.rmi.server.ServerCloneException;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static org.dromara.common.core.constant.TenantConstants.DEFAULT_TENANT_ID;

@Slf4j
@RestController
@RequestMapping("/sms")
@RequiredArgsConstructor
public class SmsLoginController {

    @DubboReference(timeout = 20000)
    private final RemoteUserService remoteUserService;

    @DubboReference(timeout = 20000)
    private final RemoteMessageService remoteMessageService;

    @DubboReference(timeout = 20000)
    private final RemoteClientService remoteClientService;

    private final RemoteTenantService remoteTenantService;

    private final SysLoginService sysLoginService;


    private final ScheduledExecutorService scheduledExecutorService;

    /**
     * 发送短信验证码
     */
    @SaIgnore
    @PostMapping("/send")
    public R<Void> sendSms(@RequestBody SmsSendRequest request) {
        ValidatorUtils.validate(request);

        // 1. 生成 6 位验证码
        String code = RandomUtil.randomNumbers(6);

        String key = GlobalConstants.CAPTCHA_CODE_KEY + request.getPhone();

        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));

        // 3. 调用短信接口
        try {
            SmsSendTestClient client = new SmsSendTestClient("http://192.167.111.239:5000/", "1");
            // 拼接短信内容
            String content = "【云时代】您的验证码是：" + code + "，5分钟内有效。";
            client.sendSms("700081", "SXzwy@DX123", request.getPhone(), content);
        } catch (Exception e) {
            log.error("短信发送失败", e);
            throw new ServiceException("短信发送失败，请稍后重试");
        }

        log.info("已发送短信验证码 [{}] 到手机号 [{}]", code, request.getPhone());
        return R.ok("验证码发送成功");
    }


    /**
     * 验证码登录
     */
    @SaIgnore
    @PostMapping("/smsLogin")
    public R<LoginVo> smsLogin(@RequestBody String body) throws ServerCloneException {
        LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
        ValidatorUtils.validate(loginBody);
        // 授权类型和客户端id
        String clientId = loginBody.getClientId();
        String grantType = loginBody.getGrantType();
        RemoteClientVo clientVo = remoteClientService.queryByClientId(clientId);
        String phone = loginBody.getPhone();
        String code = loginBody.getPhoneCode();

        // 1. 校验验证码是否正确（从Redis取）
        String cacheKey = "SMS_CODE_" + phone;
        String cachedCode = RedisUtils.getCacheObject(cacheKey);
        if (cachedCode == null || !cachedCode.equals(code)) {
            return R.fail("验证码错误或已过期");
        }
        // 查询不到 client 或 client 内不包含 grantType
        if (ObjectUtil.isNull(clientVo) || !StringUtils.contains(clientVo.getGrantType(), grantType)) {
            log.info("客户端id: {} 认证类型：{} 异常!.", clientId, grantType);
            return R.fail(MessageUtils.message("auth.grant.type.error"));
        } else if (!UserConstants.NORMAL.equals(clientVo.getStatus())) {
            return R.fail(MessageUtils.message("auth.grant.type.blocked"));
        }
        //租户由委办局通过字典获取
        String wbjKey = loginBody.getWbjKey();
        if (wbjKey != null) {
            List<RemoteTenantVo> remoteTenantVos = remoteTenantService.queryList();
            for (RemoteTenantVo remoteTenantVo : remoteTenantVos) {
                if (wbjKey.equals(remoteTenantVo.getDomain())) {
                    loginBody.setTenantId(remoteTenantVo.getTenantId());

                    Map<String, Object> jsonMap = JsonUtils.parseMap(body);
                    jsonMap.put("tenantId", remoteTenantVo.getTenantId());
                    body = JsonUtils.toJsonString(jsonMap);

                }
            }
        }
        // 校验租户
        sysLoginService.checkTenant(loginBody.getTenantId());
        // 登录
        LoginVo loginVo = IAuthStrategy.login(body, clientVo, grantType);
        RedisUtils.setCacheObject("loginUrl" + LoginHelper.getUserId(), loginBody.getLoginUrl());
        Long userId = LoginHelper.getUserId();
        scheduledExecutorService.schedule(() -> {
            remoteMessageService.publishMessage(userId, "欢迎登录专家库集约化管理平台");
        }, 3, TimeUnit.SECONDS);
        return R.ok(loginVo);
    }


    // DTO：验证码发送
    @Data
    public static class SmsSendRequest {
        @NotBlank(message = "手机号不能为空")
        private String phone;
    }

}

