package com.usoftchina.qywx.sdk;

import com.usoftchina.qywx.sdk.config.Agent;
import com.usoftchina.qywx.sdk.config.QywxProperties;
import com.usoftchina.qywx.sdk.dto.*;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 通讯录管理
 *
 * @author yingp
 */
public class AddrBookSdk extends BaseSdk {
    /**
     * 通讯录管理私钥
     * <p>使用应用secret只能进行“查询”、“邀请”等非写操作，而且只能操作应用可见范围内的通讯录</p>
     */
    public final static String ADDRESS_BOOK_AGENT_CODE = "AddressBook";

    public AddrBookSdk(QywxProperties properties) {
        super(properties);
    }

    /**
     * 是否启用
     *
     * @return
     */
    public boolean enabled() {
        Agent agent = getAgentMap().get(ADDRESS_BOOK_AGENT_CODE);
        return null != agent && null != agent.getSecret();
    }

    /**
     * sdk是否只有读权限
     *
     * @return
     */
    public boolean isReadonly() {
        return enabled() && getAgentMap().get(ADDRESS_BOOK_AGENT_CODE).isReadonly();
    }

    /**
     * 创建成员
     *
     * @param req
     */
    public void createUser(CreateUserReq req) {
        tryAndIgnoreSystemError(() ->
                restTemplate.postForEntity(baseUrl + "/cgi-bin/user/create?access_token={access_token}",
                        req.build(), BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)))
        );
    }

    /**
     * 读取成员
     *
     * @param userId 成员UserID。对应管理端的帐号，企业内必须唯一。不区分大小写，长度为1~64个字节
     */
    public GetUserResp getUser(String userId) {
        ResponseEntity<GetUserResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/get?access_token={access_token}&userid={userid}",
                GetUserResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)).addAttribute("userid", userId));
        assertOK(resp);
        return resp.getBody();
    }

    /**
     * 更新成员
     *
     * @param req
     */
    public void updateUser(UpdateUserReq req) {
        tryAndIgnoreSystemError(() ->
                restTemplate.postForEntity(baseUrl + "/cgi-bin/user/update?access_token={access_token}",
                        req.build(), BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)))
        );
    }

    /**
     * 删除成员
     *
     * @param userId 成员UserID。对应管理端的帐号
     */
    public void deleteUser(String userId) {
        tryAndIgnoreSystemError(() ->
                restTemplate.getForEntity(baseUrl + "/cgi-bin/user/delete?access_token={access_token}&userid={userid}",
                        BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)).addAttribute("userid", userId))
        );
    }

    /**
     * 批量删除成员
     *
     * @param userIdList 成员UserID列表。对应管理端的帐号。最多支持200个。若存在无效UserID，直接返回错误
     */
    public void deleteUser(List<String> userIdList) {
        tryAndIgnoreSystemError(() ->
                restTemplate.postForEntity(baseUrl + "/cgi-bin/user/batchdelete?access_token={access_token}",
                        new ModelMap("useridlist", userIdList),
                        BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)))
        );
    }

    /**
     * 获取部门成员
     *
     * @param departmentId 部门ID
     * @param fetchChild   是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门
     */
    public List<GetSimpleUserListResp.User> getSimpleUserList(Integer departmentId, boolean fetchChild) {
        ResponseEntity<GetSimpleUserListResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/simplelist?access_token={access_token}&department_id={department_id}&fetch_child={fetch_child}",
                GetSimpleUserListResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                        .addAttribute("department_id", departmentId)
                        .addAttribute("fetch_child", fetchChild ? 1 : 0));
        assertOK(resp);
        return resp.getBody().getUserlist();
    }

    /**
     * 获取部门成员详情
     *
     * @param departmentId 部门ID
     * @param fetchChild   是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门
     * @return
     */
    public List<GetUserListResp.User> getUserList(Integer departmentId, boolean fetchChild) {
        ResponseEntity<GetUserListResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/list?access_token={access_token}&department_id={department_id}&fetch_child={fetch_child}",
                GetUserListResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                        .addAttribute("department_id", departmentId)
                        .addAttribute("fetch_child", fetchChild ? 1 : 0));
        assertOK(resp);
        return resp.getBody().getUserlist();
    }

    /**
     * userid转openid
     * <p>该接口使用场景为企业支付，在使用企业红包和向员工付款时，需要自行将企业微信的userid转成openid。</p>
     *
     * @param userId
     * @return
     */
    public String getOpenId(String userId) {
        ResponseEntity<GetOpenIdResp> resp = restTemplate.postForEntity(baseUrl + "/cgi-bin/user/convert_to_openid?access_token={access_token}",
                new ModelMap("userid", userId),
                GetOpenIdResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)));
        assertOK(resp);
        return resp.getBody().getOpenid();
    }

    /**
     * 二次验证
     * <p>
     * 企业在开启二次验证时，必须在管理端填写企业二次验证页面的url。
     * 当成员登录企业微信或关注微工作台（原企业号）加入企业时，会自动跳转到企业的验证页面。在跳转到企业的验证页面时，会带上如下参数：code=CODE。
     * 企业收到code后，使用“通讯录同步助手”调用接口“根据code获取成员信息”获取成员的userid。然后在验证成员信息成功后，调用如下接口即可让成员成功加入企业
     * </p>
     *
     * @param userId
     */
    public void authSuccess(String userId) {
        ResponseEntity<BaseResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/authsucc?access_token={access_token}&userid={userid}",
                BaseResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                        .addAttribute("userid", userId));
        assertOK(resp);
    }

    /**
     * 邀请成员
     * <p>企业可通过接口批量邀请成员使用企业微信，邀请后将通过短信或邮件下发通知</p>
     *
     * @param req
     */
    public InviteResp invite(InviteReq req) {
        ResponseEntity<InviteResp> resp = restTemplate.postForEntity(baseUrl + "/cgi-bin/batch/invite?access_token={access_token}",
                req.build(), InviteResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)));
        assertOK(resp);
        return resp.getBody();
    }

    /**
     * 获取加入企业二维码
     *
     * @param type 尺寸
     * @return 二维码链接，有效期7天
     */
    public String getJoinQrCode(QrCodeType type) {
        ResponseEntity<GetJoinQrCodeResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/corp/get_join_qrcode?access_token={access_token}&size_type={size_type}",
                GetJoinQrCodeResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                        .addAttribute("size_type", type.code));
        assertOK(resp);
        return resp.getBody().getJoin_qrcode();
    }

    /**
     * qrcode尺寸类型
     */
    public enum QrCodeType {
        T_171_171(1),
        T_399_399(2),
        T_741_741(3),
        T_2052_2052(4);

        private final int code;

        QrCodeType(int code) {
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }

    /**
     * 创建部门
     *
     * @param req
     * @return 部门ID
     */
    public Integer createDepartment(CreateDepartmentReq req) {
        ResponseEntity<CreateDepartmentResp> resp = tryAndIgnoreSystemError(() ->
                restTemplate.postForEntity(baseUrl + "/cgi-bin/department/create?access_token={access_token}",
                        req.build(), CreateDepartmentResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)))
        );
        return null == resp ? null : resp.getBody().getId();
    }

    /**
     * 更新部门
     *
     * @param req
     */
    public void updateDepartment(UpdateDepartmentReq req) {
        tryAndIgnoreSystemError(() ->
                restTemplate.postForEntity(baseUrl + "/cgi-bin/department/update?access_token={access_token}",
                        req.build(), BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)))
        );
    }

    /**
     * 删除部门
     *
     * @param departmentId
     */
    public void deleteDepartment(int departmentId) {
        tryAndIgnoreSystemError(() ->
                restTemplate.getForEntity(baseUrl + "/cgi-bin/department/delete?access_token={access_token}&id={id}",
                        BaseResp.class,
                        new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                                .addAttribute("id", departmentId))
        );
    }

    /**
     * 获取部门
     *
     * @param departmentId
     * @return
     */
    public GetDepartmentListResp.Department getDepartment(int departmentId) {
        List<GetDepartmentListResp.Department> departmentList = getDepartmentList(departmentId);
        if (!CollectionUtils.isEmpty(departmentList)) {
            for (GetDepartmentListResp.Department department : departmentList) {
                if (department.getId().equals(departmentId)) {
                    return department;
                }
            }
        }
        return null;
    }

    /**
     * 获取部门，包括下级
     *
     * @param departmentId
     * @return
     */
    public List<GetDepartmentListResp.Department> getDepartmentList(int departmentId) {
        ResponseEntity<GetDepartmentListResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/list?access_token={access_token}&id={id}",
                GetDepartmentListResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE))
                        .addAttribute("id", departmentId));
        assertOK(resp);
        if (!CollectionUtils.isEmpty(resp.getBody().getDepartment())) {
            return resp.getBody().getDepartment();
        }
        return null;
    }

    /**
     * 获取部门列表
     *
     * @return
     */
    public List<GetDepartmentListResp.Department> getDepartmentList() {
        ResponseEntity<GetDepartmentListResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/department/list?access_token={access_token}",
                GetDepartmentListResp.class,
                new ModelMap("access_token", getAccessToken(ADDRESS_BOOK_AGENT_CODE)));
        assertOK(resp);
        return resp.getBody().getDepartment();
    }

    /**
     * 获取访问用户身份
     *
     * @param agentCode 应用编号
     * @param code      授权码
     */
    public GetUserInfoResp getUserInfo(String agentCode, String code) {
        ResponseEntity<GetUserInfoResp> resp = restTemplate.getForEntity(baseUrl + "/cgi-bin/user/getuserinfo?access_token={access_token}&code={code}",
                GetUserInfoResp.class,
                new ModelMap("access_token", getAccessToken(agentCode))
                        .addAttribute("code", code));
        assertOK(resp);
        return resp.getBody();
    }
}
