package com.tuoheng.admin.service.oidc.impl;

import com.alibaba.fastjson.JSONObject;
import com.tuoheng.admin.constant.OidcConstant;
import com.tuoheng.admin.dto.ClientRoleDto;
import com.tuoheng.admin.dto.ProfileResultDto;
import com.tuoheng.admin.dto.TokenResultDto;
import com.tuoheng.admin.service.oidc.OidcLoginService;
import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Base64;
import java.util.List;

@Service
@Slf4j
public class OidcLoginServiceImpl implements OidcLoginService {

    @Value("${oauth2.token.issuer}")
    private String tokenIssuer;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 根据第三方授权验证token 进行获取用户信息并跳转相关地址
     *
     * @return
     */
    @Override
    public JsonResult authorize() {
        String username = OidcConstant.HLCG_USERNAME;
        String password = OidcConstant.HLCG_PASSWORD;

        //通过oidc的密码模式获取授权token 等相关信息数据
        TokenResultDto tokenResult = getToken(username,password);
        tokenResult.setUserName(username);
        //此时通过token获取当前用户的相关权限信息并进行封装
        tokenResult = getClientResult(tokenResult, username);
        //数据封装完毕返回数据 以及相关地址 -> 是否重定向
        return JsonResult.success(tokenResult);
    }

    /**
     * 通过账号密码获取token
     */
    private TokenResultDto getToken(String username, String password) {


        String url = tokenIssuer + OidcConstant.OAUTH2_TOKEN;
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("password", password);
        params.add("username", username);
        params.add("grant_type", "password");
        params.add("scope", "openid profile");
        String clientSecret = OidcConstant.CLIENT_SECRET.split("}")[1];
        String userMsg = OidcConstant.CLIENT_ID + ":" + clientSecret;
        String authorization = Base64.getEncoder().encodeToString(userMsg.getBytes());

        ParameterizedTypeReference<TokenResultDto> parameterizedTypeReference =
                new ParameterizedTypeReference<TokenResultDto>() {
                };

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.add("Authorization", "Basic " + authorization);
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity(params, headers);

        ResponseEntity<TokenResultDto> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, parameterizedTypeReference);
        return response.getBody();
    }

    /**
     * 获取对应用户的相关信息
     *
     * @param tokenResult
     * @return
     */
    private TokenResultDto getClientResult(TokenResultDto tokenResult, String username) {

        String url = tokenIssuer + OidcConstant.GET_USERINFO;

        ParameterizedTypeReference<JsonResult<TokenResultDto>> parameterizedTypeReference =
                new ParameterizedTypeReference<JsonResult<TokenResultDto>>() {
                };

        HttpHeaders header = new HttpHeaders();
        header.add("Authorization", "Bearer " + tokenResult.getAccess_token());
        JSONObject object = new JSONObject();
        object.put("username", tokenResult.getUserName());
        HttpEntity httpEntity = new HttpEntity(object, header);

        ResponseEntity<JsonResult<TokenResultDto>> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, parameterizedTypeReference);

        TokenResultDto result = exchange.getBody().getData();
        //封装数据
        List<String> authorityList = result.getAuthorityList();
        List<ClientRoleDto> clientRoleDtoList = result.getClientRoleDtoList();
        tokenResult.setAuthorityList(authorityList);
        tokenResult.setClientRoleDtoList(clientRoleDtoList);
        tokenResult.setSub(result.getUserName());
        tokenResult.setUserId(result.getUserId());
        tokenResult.setUserName(result.getUserName());
        ProfileResultDto profile = new ProfileResultDto();
        BeanUtils.copyProperties(tokenResult, profile);
        profile.setSub(username);
        profile.setAzp(OidcConstant.CLIENT_ID);
        profile.setAuthority(authorityList);
        profile.setClientRoleList(clientRoleDtoList);
        tokenResult.setProfile(profile);

        return tokenResult;

    }

}
