package com.cico.nest.lcdp.boot.core.sso.controller.admin;

import cn.dev33.satoken.sso.config.SaSsoClientConfig;
import cn.dev33.satoken.sso.model.SaCheckTicketResult;
import cn.dev33.satoken.sso.processor.SaSsoClientProcessor;
import cn.dev33.satoken.sso.template.SaSsoUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.cico.nest.lcdp.boot.api.system.enums.ErrorCodeConstants;
import com.cico.nest.lcdp.boot.api.system.enums.logger.LoginLogTypeEnum;
import com.cico.nest.lcdp.boot.core.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.cico.nest.lcdp.boot.core.system.dal.dataobject.user.AdminUserDO;
import com.cico.nest.lcdp.boot.core.system.service.auth.AdminAuthService;
import com.cico.nest.lcdp.boot.core.system.service.user.AdminUserService;
import com.cico.nest.lcdp.boot.security.config.SecurityProperties;
import com.cico.nest.lcdp.boot.security.core.util.SecurityFrameworkUtils;
import com.cico.nest.lcdp.framework.common.pojo.CommonResult;
import com.dtflys.forest.Forest;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/***
 * 单点登录客户端（前后端分离模式）
 *
 * @author qianf
 * @date 2024/7/17 14:04
 */
@RestController
@Slf4j
@PermitAll
public class AdminClientController {
	@Resource
	private AdminUserService adminUserService;
	@Resource
	private AdminAuthService authService;
	@Resource
	private SecurityProperties securityProperties;
    // 当前是否登录
    @RequestMapping("/sso/isLogin")
    @Operation(summary = "sso是否登录")
    public CommonResult isLogin() {
        return CommonResult.success(StpUtil.isLogin());
    }

    // 返回SSO认证中心登录地址
    @RequestMapping("/sso/getSsoAuthUrl")
    public CommonResult getSsoAuthUrl(String clientLoginUrl) {
        String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
        return CommonResult.success(serverAuthUrl);
    }

	// 根据ticket进行登录
	@RequestMapping("/sso/doLoginByTicket")
	@Operation(summary = "sso客户端ticket进行登录")
	public CommonResult doLoginByTicket(String ticket) {
		String loginId =null;
		try {
			SaCheckTicketResult ctr = SaSsoClientProcessor.instance.checkTicket(ticket, "/sso/doLoginByTicket");
			loginId = (String) ctr.loginId;
			StpUtil.login(ctr.loginId, ctr.remainSessionTimeout);
		} catch (Exception e) {
			return CommonResult.error(999,e.getMessage());
		}
		//查询当前loginid，得到手机号和租户号
//		String loginId2 = String.valueOf(StpUtil.getLoginId());
		String[] loginIDArray = loginId.split("_");
		String mobile = loginIDArray[0];
		String tenantId = loginIDArray.length==2?loginIDArray[1]:null;
		AdminUserDO user = getUserByMobile(mobile,tenantId);
		if (user==null){
			return CommonResult.error(ErrorCodeConstants.AUTH_MOBILE_NOT_EXISTS);
		}
		//创建并返回客户端token
		AuthLoginRespVO authData = authService.createTokenAfterLoginSuccess(user.getId(),user.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);;
		Map<String, Object> dataMap = new HashMap<>();
		dataMap.put("satoken",StpUtil.getTokenValue());
		dataMap.put("userInfo", user);
		dataMap.put("authInfo", authData);
		log.info("/sso/doLoginByTicket,{}",dataMap);
		return CommonResult.success(dataMap);
	}


	// 模拟客户端登录和登出页
	@RequestMapping("/sso/client/index")
	public String index() {
		String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
				"<p>当前会话是否登录：" + StpUtil.isLogin() + "</p>" +
				"<p><a href=\"javascript:location.href='/admin-api/sso/login?back=' + encodeURIComponent(location.href);\">登录</a> " +
				"<a href='/admin-api/sso/logout?back=self'>注销</a></p>";
		return str;
	}

	/**
	 * Client端登录地址，接受参数：back=登录后的跳转地址
	 * @return
	 */
	@RequestMapping("/sso/login")
	@Operation(summary = "sso客户端登录")
	public CommonResult login() {
		Object obj = SaSsoClientProcessor.instance.ssoLogin();
		return CommonResult.success(obj);
	}

	/**
	 * Client端单点注销地址（isSlo=true时打开），接受参数：back=注销后的跳转地址
	 * @return
	 */
	@RequestMapping("/sso/logout")
	@Operation(summary = "sso客户端登出")
	public CommonResult logout() {
		if (StpUtil.isLogin()){
			log.info("当前sso客户端登录loginid={},satoken={}",StpUtil.getLoginId(),StpUtil.getTokenInfo());
		}
		Object obj = SaSsoClientProcessor.instance.ssoLogout();
		return CommonResult.success(obj);
	}
	/**
	 *  Client端单点注销回调地址（isSlo=true时打开），此接口为框架回调，开发者无需关心
	 * @return
	 */
	@RequestMapping("/sso/logoutCall")
	@Operation(summary = "sso客户端单点注销回调")
	public CommonResult logoutCall() {
		Object obj = SaSsoClientProcessor.instance.ssoLogoutCall();
		return CommonResult.success(obj);
	}
	/**
	 * sso及子系统同时退出
	 * @return
	 */
	@RequestMapping("/sso/logoutAll")
	@Operation(summary = "sso全部登出系统")
	public CommonResult logoutAll(HttpServletRequest request) {
		//子系统登出
		try {
			String token = SecurityFrameworkUtils.obtainAuthorization(request,
					securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
			if (StrUtil.isNotBlank(token)) {
				authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
				log.info("系统登出 accessToken：{}",token);
			}
			//sso登出
			if (StpUtil.isLogin()){
				log.info("当前sso客户端登录情况： loginid={},satoken={}",StpUtil.getLoginId(),StpUtil.getTokenInfo());
			}
			Object obj = SaSsoClientProcessor.instance.ssoLogout();
			log.info("sso是否登录：{}",StpUtil.isLogin());
			return CommonResult.success(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return CommonResult.success(true);
	}

	public AdminUserDO getUserByMobile(String mobile, String tenantId) {
		AdminUserDO user = null;
		if ( StringUtils.isEmpty(tenantId)){
			user = adminUserService.getUserByMobile(mobile);
		}else {
			Long tenant = Long.parseLong(tenantId);
			user = adminUserService.getUserByMobile(mobile,tenant);
		}
		return  user;
	}

    // 配置SSO相关参数,这段代码不能删，否则调用/sso/doLoginByTicket 会报错
    @Autowired
    private void configSso(SaSsoClientConfig ssoClient) {
        // 配置Http请求处理器
        ssoClient.sendHttp = url -> {
            log.info("------sso客户端 发起请求：" + url);
            String resStr = Forest.get(url).executeAsString();
            log.info("------sso客户端 请求结果：" + resStr);
            return resStr;
        };
    }
}
