package com.qxgmat.service;

import com.github.pagehelper.Page;
import com.nuliji.tools.AbstractService;
import com.nuliji.tools.CipherHelp;
import com.nuliji.tools.Tools;
import com.nuliji.tools.exception.AuthException;
import com.nuliji.tools.exception.ParameterException;
import com.nuliji.tools.exception.SystemException;
import com.nuliji.tools.mybatis.Example;
import com.nuliji.tools.mybatis.NativeJsonHandler;
import com.nuliji.tools.third.OauthData;
import com.qxgmat.data.constants.enums.status.DirectionStatus;
import com.qxgmat.data.dao.UserMapper;
import com.qxgmat.data.dao.entity.User;
import com.qxgmat.data.inline.UserToken;
import com.qxgmat.help.WechatHelp;
import com.qxgmat.service.inline.UserClassService;
import com.qxgmat.service.inline.UserMessageService;
import com.qxgmat.service.inline.UserPayService;
import com.qxgmat.service.inline.UserServiceService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Created by GaoJie on 2017/11/1.
 */
@Service
public class UsersService extends AbstractService {
    final public String PLATORM_WECHAT_NATIVE = "wechat_openid_wechat";
    final public String PLATORM_WECHAT_PC = "wechat_openid_pc";
    final public String PLATORM_WECHAT = "wechat_unionid";

    @Value("${self.secret}")
    private String secret;

    private NativeJsonHandler<UserToken> tokenHandler = new NativeJsonHandler<UserToken>(UserToken.class);

    @Resource
    private UserMapper userMapper;

    @Resource
    private WechatHelp wechatHelp;

    @Resource
    private UserMessageService userMessageService;

    @Resource
    private UserPayService userPayService;

    @Resource
    private UserClassService userClassService;

    @Resource
    private UserServiceService userServiceService;

    /**
     * 生成有效期token
     * @param user
     * @return
     */
    public String getTokenByUser(User user){
        UserToken ut = new UserToken();
        ut.setId(user.getId());
        Date expire = new Date(new Date().getTime() + 86400);
        ut.setExpire(expire);
        String info = tokenHandler.toJson(ut);
        return CipherHelp.encrypt(info, CipherHelp.DES, secret);
    }

    /**
     * 解析有效期token
     * @param token
     * @return
     */
    public User getUserByToken(String token){
        // 默认测试token
        if (token.equals("1234567890")){
            return get(1);
        }else{
            String info = CipherHelp.decrypt(token, CipherHelp.DES, secret);
            UserToken ut = tokenHandler.toObject(info);
            Date expire = ut.getExpire();
            if (expire.before(new Date())){
                throw new AuthException("token错误");
            }
            return get(ut.getId());
        }
    }

    /**
     * 绑定第三方账号信息
     * @param user 当前登录用户
     * @param code
     * @param platform
     * @return
     */
    @Transactional
    public User Oauth(User user, String code, String platform){
        OauthData data;
        switch(platform){
            case "wechat_pc":
                data = wechatHelp.oauthPc(code);
                break;
            case "wechat_native":
                data = wechatHelp.oauthNative(code);
                break;
            default:
                throw new ParameterException("第三方平台"+platform+"不支持");
        }
        // 获取已关联的账号
        if (user == null){
            user = getByOpen(data.getOpenId(), data.getUnionId(), platform);
        } else {
            // 检验是否已经绑定
            User openUser = getByOpen(data.getOpenId(), data.getUnionId(), platform);
            if(openUser != null && !openUser.getId().equals(user.getId())){
                // 自动合并账号
                // 更新消息
                userMessageService.mergeUser(openUser.getId(), user.getId());
                // 更新消费记录
                userPayService.mergeUser(openUser.getId(), user.getId());
                // 更新课程信息
                userClassService.mergeUser(openUser.getId(), user.getId());
                // 更新服务信息
                userServiceService.mergeUser(openUser.getId(), user.getId());

                // 更新实名认证
                if (openUser.getRealStatus() > 0){
                    user.setRealAddress(openUser.getRealAddress());
                    user.setRealIdentity(openUser.getRealIdentity());
                    user.setRealName(openUser.getRealName());
                    user.setRealPhoto(openUser.getRealPhoto());
                    user.setRealStatus(openUser.getRealStatus());
                }

                // 删除旧账号
                delete(openUser.getId());
            }
        }
        if (user == null){
            user = new User();
            user.setAvatar(data.getAvatar());
            user.setNickname(data.getNickName());
        }
        switch(platform){
            case "wechat_pc":
                user.setWechatOpenidPc(data.getOpenId());
                user.setWechatUnionid(data.getUnionId());
                break;
            case "wechat_native":
                user.setWechatOpenidWechat(data.getOpenId());
                user.setWechatUnionid(data.getUnionId());
                user.setWechatAccessToken(data.getAccessToken());
                user.setWechatRefreshToken(data.getRefreshToken());
                user.setWechatExpireTime(data.getExpiresTime());
                break;
        }
        if (!user.getMobile().isEmpty()){
            // 直接更新数据
            edit(user);
        }

        return user;
    }

    /**
     * 通过手机号注册
     * @param mobile
     * @param inviteCode
     * @param openUser
     * @return
     */
    @Transactional
    public User register(String mobile, String inviteCode, User openUser){
        User user = getByMobile(mobile);
        if (user != null){
            throw new ParameterException("手机号已注册");
        }
        // 注册，并且绑定邀请者
        user = User.builder().mobile(mobile).build();
        if (inviteCode != null && !inviteCode.isEmpty()){
            User origin = getByInviteCode(inviteCode);
            user.setOriginId(origin.getId());
            // todo 按逻辑进行奖励
            edit(User.builder().id(origin.getId()).inviteNumber(origin.getInviteNumber() + 1).build());
        }
        // 绑定第三方登录信息
        if (openUser != null){
            user.setWechatOpenidPc(openUser.getWechatOpenidPc());
            user.setWechatOpenidWechat(openUser.getWechatOpenidWechat());
            user.setWechatExpireTime(openUser.getWechatExpireTime());
            user.setWechatUnionid(openUser.getWechatUnionid());
            user.setWechatAccessToken(openUser.getWechatAccessToken());
            user.setWechatRefreshToken(openUser.getWechatRefreshToken());
            user.setNickname(openUser.getNickname());
            user.setAvatar(openUser.getAvatar());
        }
        // 生成邀请码: 10位字符串
        user.setInviteCode(Tools.getRandomString(10));

        user = add(user);
        if(user == null)
            throw new SystemException("注册失败");
        return user;
    }

    // 获取微信快到期账号
    public Page<User> listByWechatExpire(int page, int size, Date expire){
        Example example = new Example(User.class);
        example.and(
                example.createCriteria()
                        .andLessThan("wechatExpireTime", expire)
        );
        return page(()->select(userMapper, example), page, size);
    }

    public User getByMobile(String mobile){
        User user = User.builder().mobile(mobile).build();
        return one(userMapper, user);
    }

    public User getByOpen(String openId, String unionId, String platform){
        String platformField;
        String unionField;
        switch(platform){
            case "wechat_pc":
                platformField = PLATORM_WECHAT_PC;
                unionField = PLATORM_WECHAT;
                break;
            case "wechat_native":
                platformField = PLATORM_WECHAT_NATIVE;
                unionField = PLATORM_WECHAT;
                break;
            default:
                throw new ParameterException("第三方平台"+platform+"不支持");
        }
        Example example = new Example(User.class);
        example.or(
                example.createCriteria()
                        .andEqualTo(platformField, openId)
        );
        if (unionId != null && !unionId.isEmpty()){
            example.or(
                    example.createCriteria()
                    .andEqualTo(unionField, unionId)
            );
        }
        return one(userMapper, example);
    }

    public User getByInviteCode(String inviteCode){
        User user = new User();
        Example example = new Example(User.class);
        // 查找手机或邀请码
        example.and(
                example.createCriteria()
                        .orEqualTo("invite_code", inviteCode)
                        .orEqualTo("mobile", inviteCode)
        );
        return one(userMapper, example);
    }

    public boolean equalsPassword(User user, String password){
        return Objects.equals(user.getPassword(), Tools.stringMD5(Tools.stringMD5(password)));
    }

    public boolean changePassword(User user, String password){
        User updateUser = User.builder().id(user.getId()).password(Tools.stringMD5(Tools.stringMD5(password))).build();
        int result = update(userMapper, updateUser);
        return result > 0;
    }

    public User add(User user){
        if(user.getPassword() != null) user.setPassword(Tools.stringMD5(user.getPassword()));

        int result = insert(userMapper, user);
        user = one(userMapper, user.getId());
        if(user == null){
            throw new SystemException("用户添加失败");
        }
        return user;
    }

    public User edit(User user){
        User in = one(userMapper, user.getId());
        if(in == null){
            throw new ParameterException("用户不存在");
        }
        if(user.getPassword() != null) user.setPassword(Tools.stringMD5(user.getPassword()));
        int result = update(userMapper, user);
        return user;
    }

    public boolean delete(Number id){
        User in = one(userMapper, id);
        if(in == null){
            throw new ParameterException("用户不存在");
        }
        int result = delete(userMapper, id);
        return result > 0;
    }

    public User get(Number id){
        User in = one(userMapper, id);

        if(in == null){
            throw new ParameterException("用户不存在");
        }
        return in;
    }

    public Page<User> select(int page, int pageSize){return select(userMapper, page, pageSize);
    }
    public Page<User> select(int page, int pageSize, String keyword, Boolean real, String order, DirectionStatus direction){
        Example example = new Example(User.class);
        if(!keyword.isEmpty())
            example.and(
                    example.createCriteria()
                            .orLike("id", "%"+keyword+"%")
                            .orLike("mobile", "%"+keyword+"%")
            );
        if (real != null)
            example.and(
                    example.createCriteria().andEqualTo("realStatus", real?1:0)
            );
        if(order==null||order.isEmpty()) order = "id";
        if (direction != null){
            switch(direction){
                case ASC:
                    example.orderBy(order).asc();
                    break;
                case DESC:
                default:
                    example.orderBy(order).desc();
            }
        } else {
            example.orderBy(order).desc();
        }
        return select(userMapper, example, page, pageSize);
    }


    public List<User> select(Collection ids){
        return select(userMapper, ids);
    }
}
