package org.xyzh.system.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson2.JSON;

import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xyzh.api.auth.service.AuthService;
import org.xyzh.api.system.service.GuestService;
import org.xyzh.api.system.service.ModulePermissionService;
import org.xyzh.api.system.vo.PermissionVO;
import org.xyzh.common.core.domain.LoginDomain;
import org.xyzh.common.core.domain.LoginParam;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageRequest;
import org.xyzh.common.dto.sys.TbGuestDTO;
import org.xyzh.common.dto.sys.TbSysPermissionDTO;
import org.xyzh.common.dto.sys.TbSysUserDTO;
import org.xyzh.common.dto.sys.TbSysUserInfoDTO;
import org.xyzh.common.dto.sys.TbSysUserRoleDTO;
import org.xyzh.common.dto.sys.TbSysViewDTO;
import org.xyzh.common.utils.id.IdUtil;
import org.xyzh.common.utils.validation.ValidationUtils;
import org.xyzh.common.wechat.pojo.WeChatPhoneResult;
import org.xyzh.common.wechat.pojo.WeChatSessionResult;
import org.xyzh.common.wechat.service.WeChatMiniProgramService;
import org.xyzh.common.auth.utils.JwtTokenUtil;
import org.xyzh.common.redis.service.RedisService;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

/**
 * @description    来客控制器
 * @filename    GuestController.java
 * @author    yslg
 * @copyright xyzh
 * @since 2025-12-18
 */
@Validated
@RestController
@RequestMapping("/system/guest")
public class GuestController {

    private static final Logger logger = LoggerFactory.getLogger(GuestController.class);

    @Autowired
    private GuestService guestService;

    @DubboReference(version = "1.0.0", group = "auth", timeout = 5000, check = false, retries = 0)
    private AuthService authService;

    @Autowired
    private ModulePermissionService modulePermissionService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisService redisService;

    @Autowired
    private WeChatMiniProgramService weChatMiniProgramService;


    @PostMapping
    public ResultDomain<TbGuestDTO> createGuest(@RequestBody TbGuestDTO guest) {
        ValidationUtils.validate(guest, Arrays.asList(
            ValidationUtils.requiredString("name", "姓名"),
            ValidationUtils.atLeastOne(
                Arrays.asList("phone", "email", "wechatId"),
                Arrays.asList("电话", "邮箱", "微信ID")
            )
        ));
        return guestService.createGuest(guest);
    }

    @PutMapping
    public ResultDomain<TbGuestDTO> updateGuest(@RequestBody TbGuestDTO guest) {
        ValidationUtils.validate(guest, Arrays.asList(
            ValidationUtils.requiredString("name", "姓名"),
            ValidationUtils.atLeastOne(
                Arrays.asList("phone", "email", "wechatId"),
                Arrays.asList("电话", "邮箱", "微信ID")
            )
        ));
        return guestService.updateGuest(guest);
    }

    @DeleteMapping("/{userId}")
    public ResultDomain<TbGuestDTO> deleteGuest(@PathVariable("userId") @NotNull String userId) {
        return guestService.deleteGuest(userId);
    }

    @GetMapping("/wechat/{wechatId}")
    public ResultDomain<TbGuestDTO> selectGuestByWechat(@PathVariable("wechatId") @NotBlank String wechatId){
        return guestService.selectGuestByWechatId(wechatId);
    }


    @PostMapping("/list")
    public ResultDomain<TbGuestDTO> listGuest(@RequestBody TbGuestDTO filter) {
        return guestService.selectGuestList(filter);
    }

    @PostMapping("/page")
    public ResultDomain<TbGuestDTO> pageGuest(@RequestBody PageRequest<TbGuestDTO> pageRequest) {
        return guestService.selectGuestPage(pageRequest);
    }

    // ========================= 微信小程序用户识别登录 =========================

    /**
     * 模拟用户数据（用于测试，没有手机号校验appid时使用）
     * 格式：手机号 -> [姓名, 微信ID, 角色]
     */
    private static final java.util.Map<String, String[]> MOCK_USERS = new java.util.HashMap<String, String[]>() {{
        put("17857100375", new String[]{"超级管理员", "17857100375", "admin"});
        put("13870055185", new String[]{"魏瑶", "75719954", "engineer"});
        put("15170466624", new String[]{"刘杰", "liujie1370984851", "engineer"});
        put("15170037929", new String[]{"万家明", "WJM15170037929", "engineer"});
        put("19100185270", new String[]{"戴斌", "BaiBin0714", "guest"});
        put("15797790517", new String[]{"余其跃", "a540378218", "guest"});
        put("15879126468", new String[]{"李小华", "wxid_vgmmzfdcwx9021", "guest"});
    }};

    @Operation(summary = "微信小程序用户识别登录")
    @PostMapping("/identify")
    public ResultDomain<LoginDomain> identifyUser(@RequestBody LoginParam loginParam, HttpServletRequest request) {
        logger.info("微信小程序登录请求: wechatId={}, phone={}, mockMode={}", 
                loginParam.getWechatId(), 
                loginParam.getPhone(),
                loginParam.getMockMode() != null ? loginParam.getMockMode() : false);
        
        // ========== 模拟模式：直接使用传入的手机号匹配用户 ==========
        if (Boolean.TRUE.equals(loginParam.getMockMode()) && loginParam.getPhone() != null) {
            String phone = loginParam.getPhone().trim();
            String[] mockUser = MOCK_USERS.get(phone);
            
            if (mockUser != null) {
                // 设置模拟用户信息
                loginParam.setUsername(mockUser[0]);
                loginParam.setWechatId(mockUser[1]);
                logger.info("模拟登录: phone={}, name={}, wechatId={}, role={}", 
                        phone, mockUser[0], mockUser[1], mockUser[2]);
            } else {
                return ResultDomain.failure("未找到该手机号对应的测试用户");
            }
        } else {
            // ========== 正常模式：通过微信API获取手机号 ==========
            // 1. 处理微信登录code，获取openid
            String openid = null;
            String sessionKey = null;
            if (loginParam.getCode() != null && !loginParam.getCode().trim().isEmpty()) {
                ResultDomain<WeChatSessionResult> sessionResult = weChatMiniProgramService.code2Session(loginParam.getCode());
                if (sessionResult.getSuccess() && sessionResult.getData() != null) {
                    openid = sessionResult.getData().getOpenid();
                    sessionKey = sessionResult.getData().getSessionKey();
                    logger.info("获取openid成功: {}", openid);
                    loginParam.setWechatId(openid);
                } else {
                    logger.warn("获取openid失败: {}", sessionResult.getMessage());
                }
            }
            
            // 2. 处理手机号授权
            String phoneNumber = null;
            
            // 方式1：使用phoneCode获取手机号（新版API，推荐）
            if (loginParam.getPhoneCode() != null && !loginParam.getPhoneCode().trim().isEmpty()) {
                ResultDomain<WeChatPhoneResult> phoneResult = weChatMiniProgramService.getPhoneNumber(loginParam.getPhoneCode());
                if (phoneResult.getSuccess() && phoneResult.getData() != null && phoneResult.getData().getPhoneInfo() != null) {
                    phoneNumber = phoneResult.getData().getPhoneInfo().getPurePhoneNumber();
                    if (phoneNumber == null) {
                        phoneNumber = phoneResult.getData().getPhoneInfo().getPhoneNumber();
                    }
                    logger.info("通过phoneCode获取手机号成功: {}", phoneNumber);
                } else {
                    logger.warn("通过phoneCode获取手机号失败: {}", phoneResult.getMessage());
                }
            }
            
            // 方式2：使用encryptedData和iv解密手机号（旧版API）
            if (phoneNumber == null && sessionKey != null 
                    && loginParam.getEncryptedData() != null && !loginParam.getEncryptedData().trim().isEmpty()
                    && loginParam.getIv() != null && !loginParam.getIv().trim().isEmpty()) {
                ResultDomain<String> decryptResult = weChatMiniProgramService.decryptPhoneNumber(
                        sessionKey, loginParam.getEncryptedData(), loginParam.getIv());
                if (decryptResult.getSuccess() && decryptResult.getData() != null) {
                    phoneNumber = decryptResult.getData();
                    logger.info("通过解密获取手机号成功: {}", phoneNumber);
                } else {
                    logger.warn("解密手机号失败: {}", decryptResult.getMessage());
                }
            }
            
            // 设置手机号
            if (phoneNumber != null) {
                loginParam.setPhone(phoneNumber);
            }
        }
        
        // 验证参数：必须有wechatId或phone
        if ((loginParam.getWechatId() == null || loginParam.getWechatId().trim().isEmpty()) 
            && (loginParam.getPhone() == null || loginParam.getPhone().trim().isEmpty())) {
            return ResultDomain.failure("微信ID或手机号不能为空");
        }

        // 设置登录类型为微信小程序
        loginParam.setLoginType("wechat_miniprogram");
        
        // 从 request 中提取客户端 IP 并设置到 loginParam
        loginParam.setClientIp(getClientIP(request));

        // 3. 尝试通过AuthService登录（员工）
        ResultDomain<LoginDomain> loginResult = authService.login(loginParam);
        if (loginResult.getSuccess() && loginResult.getData() != null) {
            // 登录成功，是系统员工
            logger.info("员工登录成功: userId={}", loginResult.getData().getUser().getUserId());
            return loginResult;
        }

        // 4. 登录失败，查询/注册来客
        return handleGuestLogin(loginParam);
    }

    /**
     * 处理来客登录：查询或注册来客，构造LoginDomain
     */
    private ResultDomain<LoginDomain> handleGuestLogin(LoginParam loginParam) {
        TbGuestDTO guest = null;

        // 优先用wechatId查询
        if (loginParam.getWechatId() != null && !loginParam.getWechatId().trim().isEmpty()) {
            ResultDomain<TbGuestDTO> guestResult = guestService.selectGuestByWechatId(loginParam.getWechatId());
            if (guestResult.getSuccess() && guestResult.getData() != null) {
                guest = guestResult.getData();
            }
        }

        // wechatId未找到，尝试用phone查询
        if (guest == null && loginParam.getPhone() != null && !loginParam.getPhone().trim().isEmpty()) {
            TbGuestDTO filter = new TbGuestDTO();
            filter.setPhone(loginParam.getPhone());
            ResultDomain<TbGuestDTO> guestResult = guestService.selectGuestOne(filter);
            if (guestResult.getSuccess() && guestResult.getData() != null) {
                guest = guestResult.getData();
                // 如果来客存在但wechatId为空，更新wechatId
                if (guest.getWechatId() == null && loginParam.getWechatId() != null) {
                    TbGuestDTO updateGuest = new TbGuestDTO();
                    updateGuest.setUserId(guest.getUserId());
                    updateGuest.setWechatId(loginParam.getWechatId());
                    guestService.updateGuest(updateGuest);
                    guest.setWechatId(loginParam.getWechatId());
                }
            }
        }

        // 3. 来客不存在，创建新来客
        if (guest == null) {
            TbGuestDTO newGuest = new TbGuestDTO();
            newGuest.setOptsn(IdUtil.getOptsn());
            newGuest.setUserId(IdUtil.generateID());
            newGuest.setWechatId(loginParam.getWechatId());
            newGuest.setPhone(loginParam.getPhone());
            newGuest.setName(loginParam.getUsername() != null ? loginParam.getUsername() : "来客");
            
            ResultDomain<TbGuestDTO> createResult = guestService.createGuest(newGuest);
            if (!createResult.getSuccess()) {
                return ResultDomain.failure("创建来客失败: " + createResult.getMessage());
            }
            guest = createResult.getData();
        }

        // 4. 构造来客的LoginDomain
        return ResultDomain.success("来客登录成功", buildGuestLoginDomain(guest));
    }

    /**
     * 从来客信息构造LoginDomain
     */
    private LoginDomain buildGuestLoginDomain(TbGuestDTO guest) {
        LoginDomain loginDomain = new LoginDomain();

        // 构造TbSysUserDTO，status设为guest
        TbSysUserDTO userDTO = new TbSysUserDTO();
        userDTO.setUserId(guest.getUserId());
        userDTO.setPhone(guest.getPhone());
        userDTO.setEmail(guest.getEmail());
        userDTO.setWechatId(guest.getWechatId());
        userDTO.setStatus("guest");  // 来客特殊状态
        loginDomain.setUser(userDTO);

        // 构造TbSysUserInfoDTO
        TbSysUserInfoDTO userInfoDTO = new TbSysUserInfoDTO();
        userInfoDTO.setUserId(guest.getUserId());
        userInfoDTO.setUsername(guest.getName());
        loginDomain.setUserInfo(userInfoDTO);

        // 设置角色信息
        List<TbSysUserRoleDTO> userRoles = new ArrayList<>();
        TbSysUserRoleDTO userRole = new TbSysUserRoleDTO();
        userRole.setUserId(guest.getUserId());
        userRole.setRoleId("role_guest");
        userRole.setDeptId("dept_root");
        userRoles.add(userRole);
        loginDomain.setUserRoles(userRoles);

        // 获取用户权限信息
        List<TbSysPermissionDTO> userPermissions = new ArrayList<>();
        List<TbSysViewDTO> userViews = new ArrayList<>();
        
        ResultDomain<PermissionVO> permissionsResult = modulePermissionService.getUserPermissions(guest.getUserId());
        if (permissionsResult.getSuccess() && permissionsResult.getDataList() != null) {
            for (PermissionVO permission : permissionsResult.getDataList()) {
                if (permission.getPermissionId() != null) {
                    TbSysPermissionDTO permissionDTO = PermissionVO.toPermissionDTO(permission);
                    if (permissionDTO != null) {
                        userPermissions.add(permissionDTO);
                    }
                }
                if (permission.getViewId() != null) {
                    TbSysViewDTO viewDTO = PermissionVO.toViewDTO(permission);
                    if (viewDTO != null) {
                        userViews.add(viewDTO);
                    }
                }
            }
        }
        loginDomain.setUserPermissions(userPermissions);
        loginDomain.setUserViews(userViews);

        loginDomain.setLoginType("wechat_miniprogram");

        // 生成 JWT Token
        String token = jwtTokenUtil.generateToken(loginDomain);
        loginDomain.setToken(token);

        // 将登录信息存储到 Redis（24小时有效期）
        String loginKey = "login:token:" + token;
        redisService.set(loginKey, JSON.toJSONString(loginDomain), 24, TimeUnit.HOURS);

        // 存储用户登录状态
        String userLoginKey = "login:user:" + guest.getUserId();
        redisService.set(userLoginKey, token, 24, TimeUnit.HOURS);

        return loginDomain;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIP(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
}
