package com.yunzhupaas.granter;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yunzhupaas.base.ActionResult;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.config.YunzhupaasOauthConfig;
import com.yunzhupaas.constant.MsgCode;
import com.yunzhupaas.consts.AuthConsts;
import com.yunzhupaas.consts.LoginTicketStatus;
import com.yunzhupaas.exception.LoginException;
import com.yunzhupaas.model.BaseSystemInfo;
import com.yunzhupaas.model.LoginTicketModel;
import com.yunzhupaas.model.SocialUnbindModel;
import com.yunzhupaas.permission.controller.SocialsUserController;
import com.yunzhupaas.permission.model.socails.SocialsUserInfo;
import com.yunzhupaas.permission.util.implicit.ImplicitLoginUtil;
import com.yunzhupaas.util.ServletUtil;
import com.yunzhupaas.util.StringUtil;
import com.yunzhupaas.util.TicketUtil;
import com.yunzhupaas.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

import static com.yunzhupaas.granter.ImplicitTokenGranter.GRANT_TYPE;

@Slf4j
@Component(GRANT_TYPE)
public class ImplicitTokenGranter extends AbstractTokenGranter {

    public static final String GRANT_TYPE = "implicit";
    public static final Integer ORDER = 5;
    private static final String URL_LOGIN = "/Login/implicit/**";

    @Autowired
    private ImplicitLoginUtil implicitLoginUtil;

    @Autowired
    private SocialsUserController socialsUserApi;

    @Autowired
    private YunzhupaasOauthConfig oauthConfig;

    public ImplicitTokenGranter() {
        super(URL_LOGIN);
    }

    protected String getGrantType() {
        return GRANT_TYPE;
    }

    public ActionResult logout() {
        return super.logout();
    }

    public int getOrder() {
        return ORDER;
    }

    @Override
    protected void loginSuccess(UserInfo userInfo, BaseSystemInfo baseSystemInfo) {
    }

    @Override
    protected void loginFailure(UserInfo userInfo, BaseSystemInfo baseSystemInfo, Exception e) {
        super.loginFailure(userInfo, baseSystemInfo, e);
    }

    @Override
    protected String getUserDetailKey() {
        return AuthConsts.USERDETAIL_USER_ID;
    }

    public ActionResult granter(Map<String, String> map) throws LoginException {
        SaRequest req = SaHolder.getRequest();
        String code = req.getParam("code");
        String source = req.getParam("source");
        String userAgent = ServletUtil.getUserAgent();
        if (userAgent.contains("wxwork")) {
            source = "wechat_enterprise";
        }
        if (userAgent.contains("DingTalk")) {
            source = "dingtalk";
        }
        // 授权回调，登录接口，重定向携带token的首页
        if (StringUtil.isEmpty(source)) {
            return ActionResult.fail(MsgCode.OA028.get());
        }
        // 跳js页面，直接调用授权链接
        if (StringUtil.isEmpty(code)) {
            String authLink = implicitLoginUtil.getAuthLink(source);
            SaHolder.getResponse().redirect(authLink);
            return null;
        }
        String uuid = implicitLoginUtil.loginByCode(source, code, null);
        // uuid登录
        return this.loginByUuid(source, uuid);
    }

    /**
     * 通过第三方用户id登录
     * 
     * @param source
     * @param uuid
     * @return
     * @throws LoginException
     */
    protected ActionResult loginByUuid(String source, String uuid) throws LoginException {
        boolean isApp = "APP".equalsIgnoreCase(UserProvider.getDeviceForAgent().getDevice());
        String url = isApp ? configValueUtil.getAppDomain() : configValueUtil.getFrontDomain();
        SocialsUserInfo socialsUserInfo = socialsUserApi.getUserInfo(source, uuid, null);
        if (configValueUtil.isMultiTenancy()) {
            if (socialsUserInfo == null || CollectionUtil.isEmpty(socialsUserInfo.getTenantUserInfo())) {
                // 未绑定写入缓存
                LoginTicketModel ticketModel = (new LoginTicketModel())
                        .setStatus(LoginTicketStatus.UnBindMes.getStatus())
                        .setTicketTimeout(System.currentTimeMillis() + oauthConfig.getTicketTimeout() * 1000);
                createdTicketState(ticketModel, url, isApp);
                return ActionResult.success();
            }
            if (socialsUserInfo.getTenantUserInfo().size() == 1) {
                UserInfo userInfo = socialsUserInfo.getUserInfo();
                // 切换租户
                switchTenant(userInfo);
                // 获取系统配置
                BaseSystemInfo baseSystemInfo = getSysconfig(userInfo);
                // 登录账号
                String token = super.loginAccount(userInfo, baseSystemInfo);
                // 返回登录信息
                String redirectUrl = url + "/sso" + "?token=" + token;
                if (isApp) {
                    redirectUrl = url + "/pages/login/sso-redirect" + "?token=" + token;
                }
                SaHolder.getResponse().redirect(redirectUrl);
                return ActionResult.success();
            } else {
                // 多租户信息写入ticket缓存
                JSONArray tenantUserInfo = socialsUserInfo.getTenantUserInfo();
                LoginTicketModel ticketModel = (new LoginTicketModel())
                        .setStatus(LoginTicketStatus.Multitenancy.getStatus()).setValue(tenantUserInfo.toJSONString())
                        .setTicketTimeout(System.currentTimeMillis() + oauthConfig.getTicketTimeout() * 1000);
                createdTicketState(ticketModel, url, isApp);
                return ActionResult.success();
            }
        } else {
            if (socialsUserInfo == null || socialsUserInfo.getUserInfo() == null) {
                // 未绑定写入缓存
                LoginTicketModel ticketModel = (new LoginTicketModel())
                        .setStatus(LoginTicketStatus.UnBindMes.getStatus())
                        .setTicketTimeout(System.currentTimeMillis() + oauthConfig.getTicketTimeout() * 1000);
                createdTicketState(ticketModel, url, isApp);
                return ActionResult.success();
            }
            UserInfo userInfo = socialsUserInfo.getUserInfo();
            // 切换租户
            switchTenant(userInfo);
            // 获取系统配置
            BaseSystemInfo baseSystemInfo = getSysconfig(userInfo);
            // 登录账号
            String token = super.loginAccount(userInfo, baseSystemInfo);
            String redirectUrl = url + "/sso" + "?token=" + token;
            if (isApp) {
                redirectUrl = url + "/pages/login/sso-redirect" + "?token=" + token;
            }
            SaHolder.getResponse().redirect(redirectUrl);
            return ActionResult.success();
        }
    }

    /**
     * 创建票据
     * 
     * @param loginTicketModel
     * @param url
     * @param isApp
     * @return
     */
    private String createdTicketState(LoginTicketModel loginTicketModel, String url, boolean isApp) {
        String ticket = TicketUtil.createTicket(loginTicketModel, oauthConfig.getTicketTimeout());
        String MultitenancyUrl = url + "/login?YUNZHUPAAS_TICKET=" + ticket;
        if (isApp) {
            MultitenancyUrl = url + "/pages/login/index?YUNZHUPAAS_TICKET=" + ticket;
        }
        SaHolder.getResponse().redirect(MultitenancyUrl);
        return ticket;
    }

    /**
     * 未绑定-更新票据缓存
     *
     * @param socialType
     * @param socialUnionid
     * @param socialName
     * @return
     */
    protected LoginTicketModel updateTicketUnbind(String socialType, String socialUnionid, String socialName) {
        LoginTicketModel loginTicketModel = null;
        SocialUnbindModel obj = new SocialUnbindModel(socialType, socialUnionid, socialName);
        String ticket = this.getYunzhupaasTicket();
        if (!ticket.isEmpty()) {
            loginTicketModel = (new LoginTicketModel()).setStatus(LoginTicketStatus.UnBind.getStatus())
                    .setValue(JSONObject.toJSONString(obj));
            TicketUtil.updateTicket(ticket, loginTicketModel, (Long) 300L);
        }
        return loginTicketModel;
    }
}
