package com.kym.service.miniapp.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.kym.common.R;
import com.kym.common.config.WxConfig;
import com.kym.common.constant.ResponseEnum;
import com.kym.common.enums.WxApi;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.common.utils.HttpUtil;
import com.kym.entity.admin.queryParams.CommonQueryParam;
import com.kym.entity.admin.vo.CustomUserVo;
import com.kym.entity.common.PageBean;
import com.kym.entity.miniapp.Account;
import com.kym.entity.miniapp.Cars;
import com.kym.entity.miniapp.User;
import com.kym.entity.miniapp.params.WxLoginParams;
import com.kym.entity.miniapp.vo.UserVo;
import com.kym.entity.wechat.WxPhoneNum;
import com.kym.mapper.miniapp.UserMapper;
import com.kym.service.miniapp.AccountService;
import com.kym.service.miniapp.CarsService;
import com.kym.service.miniapp.UserService;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.Map.of;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author skyline
 * @since 2023-06-27
 */
@Service
@DS("db-miniapp")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
    final
    WxConfig wxConfig;
    private final AccountService accountService;

    private final CarsService carsService;

    public UserServiceImpl(WxConfig wxConfig, AccountService accountService, CarsService carsService) {
        this.wxConfig = wxConfig;
        this.accountService = accountService;
        this.carsService = carsService;
    }


    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    @Override
    public R wxLogin(WxLoginParams params) {
        // 微信登录
        var json = HttpUtil.getJson(WxApi.WX_MP_LOGIN.getApi(), Map.of(
                "appid", wxConfig.getAppid(),
                "secret", wxConfig.getSecret(),
                "js_code", params.getCode()
        ));

        Integer errorCode = json.getInteger("errcode");
        if (errorCode == null) {
            // 业务逻辑处理
            var openid = json.getString("openid");
            var session_key = json.getString("session_key");
            var unionid = json.getString("unionid") == null ? "" : json.getString("unionid");
            // 判断有没有，没有就新增
            var user = baseMapper.selectOne(new QueryWrapper<User>().eq("openid", openid));
            if (user != null) {
                // 登录逻辑
                return handleLogin(user);
            } else {
                // 注册逻辑
                // 新增用户
                var newUser = new User();
                newUser.setOpenid(openid);
                newUser.setUnionid(unionid);
                // 手机号解密:先获取access_token,再请求手机号信息
                // access_token获取
                var accessTokenJson = HttpUtil.getJson(WxApi.WX_GET_ACCESS_TOKEN.getApi(), Map.of("appid", wxConfig.getAppid(), "secret", wxConfig.getSecret()));
                var accessToken = accessTokenJson.getString("access_token");
                var wxPhoneNum = HttpUtil.post(WxApi.WX_MP_GET_PHONE.getApi().replace("ACCESS_TOKEN", accessToken), Map.of("code", params.getPhoneCode()), WxPhoneNum.class);
                var mobilePhone = wxPhoneNum.getPhone_info().getPurePhoneNumber();
                newUser.setMobilePhone(mobilePhone);
                newUser.setUsername(mobilePhone);
                newUser.setAvatar(params.getAvatar());
                newUser.setNickname(params.getNickname());
                baseMapper.insert(newUser);
                // 创建用户账户
                var account = new Account();
                account.setUserId(newUser.getId());
                accountService.save(account);
                // 登录逻辑
                return handleLogin(newUser);
            }

        } else {
            // 抛出异常
            LOGGER.error("微信登录异常,错误码{}，异常信息{}", errorCode, json.getString("errmsg"));
            throw new BusinessException(ResponseEnum.WX_MP_LOGIN_ERROR);
        }
    }

    /**
     * 获取当前登录用户信息
     *
     * @return
     */
    @Override
    public UserVo getMe() {
        var userId = StpUtil.getLoginIdAsLong();
        var userVo = baseMapper.getMe(userId);
        var car = carsService.lambdaQuery().eq(Cars::getUserId, userId).eq(Cars::getIsDefault, 1).one();
        if (car != null) {
            userVo.setDefaultPlateNo(car.getPlateNo());
            userVo.setVin(car.getVin());
        }
        return userVo;
    }


    /**
     * 登录逻辑处理
     *
     * @param user
     * @return
     */
    private R handleLogin(User user) {
        StpUtil.login(user.getId());
        // 用户名存入session，统一日志读取使用
        StpUtil.getSession().set("openid", user.getOpenid());
        StpUtil.getSession().set("userId", user.getId());
        StpUtil.getSession().set("mobilePhone", user.getMobilePhone());
        user.setLastLoginTime(LocalDateTime.now());
        updateById(user);
        LOGGER.info("用户：{}/{}登录成功，tokenName:{},tokenValue:{}", user.getMobilePhone(), user.getId(), StpUtil.getTokenName(), StpUtil.getTokenValue());
        return R.success(of("userId", user.getId(), "satoken", StpUtil.getTokenValue()));
    }

    @Override
    public boolean createUser(UserVo userVo) {
        var user = new User();
        user.setUsername(userVo.username);
        return save(user);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUser(UserVo userVo) {
        userVo.setId(StpUtil.getSession().getLong("userId"));
        var user = new User();
        BeanUtils.copyProperties(userVo, user);
        if (!CommUtil.isEmptyOrNull(user.getAvatar()) || !CommUtil.isEmptyOrNull(user.getMobilePhone()) || !CommUtil.isEmptyOrNull(user.getNickname())) {
            baseMapper.updateById(user);
        }
        // 更新车牌信息
        if (userVo.getDefaultPlateNo() != null) {
            var car = new Cars();
            car.setUserId(userVo.getId());
            car.setPlateNo(userVo.defaultPlateNo);
            // 设置为默认
            car.setIsDefault(true);
            if (userVo.getVin() != null) {
                car.setVin(userVo.getVin());
            }
            // 将用户名下其他车辆设为非默认
            var cars = carsService.listByMap(Map.of("user_id", userVo.getId()));
            cars.stream().filter(c -> !userVo.getDefaultPlateNo().equals(c.getEngineNo())).peek(s -> s.setIsDefault(false)).collect(Collectors.toList());
            carsService.updateBatchById(cars);
            var wrapper = new QueryWrapper<Cars>();
            wrapper.eq("plate_no", userVo.getDefaultPlateNo());
            carsService.saveOrUpdate(car, wrapper);
        }
    }

    @Override
    public PageBean<UserVo> listUserVo(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        var userVoList = list().stream().map(user -> {
            var userVo = new UserVo();
            BeanUtils.copyProperties(user, userVo);
            return userVo;
        }).collect(Collectors.toList());
        return new PageBean<>(userVoList);
    }


    /**
     * 分页查询用户列表
     *
     * @param params
     * @return
     */
    @Override
    public PageBean<CustomUserVo> listCustomUser(CommonQueryParam params) {
        Long userId = null;
        if (!CommUtil.isEmptyOrNull(params.getMobilePhone())) {
            userId = lambdaQuery().eq(User::getMobilePhone, params.getMobilePhone()).one().getId();
        }
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        var result = baseMapper.listUser(userId);
        return new PageBean<>(result);
    }


}
