package com.backendsys.service.B2c;

import com.backendsys.entity.B2c.B2cMemberDTO;
import com.backendsys.mapper.B2c.B2cMemberMapper;
import com.backendsys.modules.common.config.security.utils.JwtUtil;
import com.backendsys.utils.response.PageInfoResult;
import com.backendsys.utils.response.Result;
import com.backendsys.utils.response.ResultEnum;
import com.github.pagehelper.PageHelper;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class B2cMemberServiceImpl implements B2cMemberService {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${REDIS_LOGIN_TOKEN_PREFIX}")
    private String REDIS_LOGIN_TOKEN_PREFIX;
    @Value("${TOKEN_DURATION_MEMBER}")
    private Long TOKEN_DURATION_MEMBER;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private B2cMemberMapper b2cMemberMapper;

    /**
     * 查询 列表
     */
    public Map<String, Object> queryMemberList(Integer pageNum, Integer pageSize, B2cMemberDTO b2cMemberDTO) {
        // 分页查询
        if (pageNum != null && pageSize != null) {
            PageHelper.startPage(pageNum, pageSize);
            PageHelper.getLocalPage().setPageSizeZero(true);
        }
        // 分页输出 (自定义)
        List<Map<String, Object>> list = b2cMemberMapper.queryMemberList(b2cMemberDTO);
        PageInfoResult pageInfoResult = new PageInfoResult(list);
        return pageInfoResult.toMap();
    }

    /**
     * 查询 详情
     */
    @Override
    public Map<String, Object> queryMemberDetail(Long good_member_id) {
        return b2cMemberMapper.queryMemberDetail(good_member_id);
    }

    /**
     * 创建
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> insertMember(B2cMemberDTO b2cMemberDTO) {
        b2cMemberMapper.insertMember(b2cMemberDTO);
        return Map.of("good_member_id", b2cMemberDTO.getMember_id());
    }

    /**
     * 更新
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> updateMember(B2cMemberDTO b2cMemberDTO) {
        b2cMemberMapper.updateMember(b2cMemberDTO);
        return Map.of("good_member_id", b2cMemberDTO.getMember_id());
    }

    /**
     * 删除
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> deleteMember(B2cMemberDTO b2cMemberDTO) {
        b2cMemberMapper.deleteMember(b2cMemberDTO);
        return Map.of("good_member_id", b2cMemberDTO.getMember_id());
    }

    /** --------------------------- Member Auth Login ----------------------------- **/

    // [Method] 判断密码是否正确
    private Boolean isUserPasswordValid(Map<String, Object> userDTO, String password) {
        if (userDTO == null) return false;
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder.matches(password, (String) userDTO.get("password"));
    }

    /**
     * 查询 会员用户列表 (在线)
     */
    @Override
    public List<Map<String, Object>> queryMemberWithLogined(Integer pageNum, Integer pageSize, B2cMemberDTO b2cMemberDTO) {
        // 分页查询
        if (pageNum != null && pageSize != null) {
            PageHelper.startPage(pageNum, pageSize);
        }

        // 获得用户最后登录的UUID
        Set redisKeys = redisTemplate.keys("token:*");
        // 获得UUID数组
        Set last_login_uuids = (Set) redisKeys.stream().map(
                e -> String.valueOf(e).replace(REDIS_LOGIN_TOKEN_PREFIX, "")
        ).collect(Collectors.toSet());

        return b2cMemberMapper.queryMemberWithLogined(last_login_uuids);
    }

    /**
     * 登录 (会员用户)
     * @param b2cMemberDTO(username, password)
     * @return { token, b2cMemberDTO }
     */
    @Override
    public Result login(HttpServletRequest request, B2cMemberDTO b2cMemberDTO) {

        String phone = b2cMemberDTO.getPhone();
        String password = b2cMemberDTO.getPassword();

        // [Method] 判断 用户是否存在 && 密码是否正确
        Map<String, Object> b2cMemberDTOSimple = b2cMemberMapper.queryMemberByIdOrName(null, phone);
        if (!(b2cMemberDTOSimple != null && isUserPasswordValid(b2cMemberDTOSimple, password))) {
            return Result.error(ResultEnum.INVALID_CREDENTIALS.getCode(), "用户名或密码错误");
        }

        // [登录成功]
        // 1.[查询] 用户信息详情
        String uuid = String.valueOf(UUID.randomUUID());
        Long memberId = (Long) b2cMemberDTOSimple.get("id");
        Map<String, Object> b2cMemberDetail = b2cMemberMapper.queryMemberDetail(memberId);

        // [Redis] 删除旧 Redis Key
        String old_uuid = (String) b2cMemberDetail.get("last_login_uuid");
        if (old_uuid != null) {
            stringRedisTemplate.delete(REDIS_LOGIN_TOKEN_PREFIX + old_uuid);
        }

        //System.out.println(b2cMemberDetail);

        // 生成 Token 过期时间 (存入Token/带出Result返回值)
        Date tokenExpiration = new Date((new Date()).getTime() + TOKEN_DURATION_MEMBER);
        b2cMemberDetail.put("token_expiration", tokenExpiration);

        // 生成 Token
        b2cMemberDetail.put("last_login_uuid", uuid);
        String token = jwtUtil.createMemberToken(b2cMemberDetail);

        // 存入 Redis：Token、Token过期时间
        // String tokenRedisKey = REDIS_LOGIN_TOKEN_PREFIX + memberId;
        String tokenRedisKey = REDIS_LOGIN_TOKEN_PREFIX + uuid;
        stringRedisTemplate.opsForValue().set(tokenRedisKey, token, TOKEN_DURATION_MEMBER, TimeUnit.MILLISECONDS);

        // 6.[更新] 用户最后登录时间、登录IP
        B2cMemberDTO b2cMemberLastLogin = new B2cMemberDTO();
        b2cMemberLastLogin.setMember_id(memberId);
        b2cMemberLastLogin.setLast_login_ip(request.getRemoteAddr());
        b2cMemberLastLogin.setLast_login_uuid(uuid);
        b2cMemberLastLogin.setLast_login_time(LocalDateTime.now());
        b2cMemberMapper.updateMember(b2cMemberLastLogin);

        // 7.[格式化] 将 Token 拼接到输出结果
        Map<String, Object> result = new LinkedHashMap<>(b2cMemberDetail);
        result.remove("del_flag");

        result.put("token", token);

        return Result.success(result);
    }
}
