package com.fs.user;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fs.common.annotation.Log;
import com.fs.common.core.controller.BaseController;
import com.fs.common.core.domain.AjaxResult;
import com.fs.common.core.domain.R;
import com.fs.common.core.page.TableDataInfo;
import com.fs.common.enums.BusinessType;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.ServletUtils;
import com.fs.company.cache.ICompanyUserCacheService;
import com.fs.course.domain.FsUserCompanyUser;
import com.fs.company.domain.CompanyUser;
import com.fs.company.service.ICompanyUserService;
import com.fs.course.domain.FsUserCompanyUser;
import com.fs.course.mapper.FsUserCompanyUserMapper;
import com.fs.course.mapper.FsCourseWatchLogMapper;
import com.fs.course.domain.FsUserCoursePeriod;
import com.fs.course.dto.BatchSendCourseDTO;
import com.fs.course.param.FsCourseLinkCreateParam;
import com.fs.course.service.IFsUserCompanyUserService;
import com.fs.course.param.PeriodUserTransferParam;
import com.fs.course.service.IFsUserCompanyUserService;
import com.fs.course.service.IFsUserCoursePeriodService;
import com.fs.course.service.IFsUserCourseService;
import com.fs.framework.security.LoginUser;
import com.fs.framework.service.TokenService;
import com.fs.his.domain.FsUser;
import com.fs.his.service.IFsUserService;
import com.fs.his.utils.PhoneUtil;
import com.fs.im.dto.OpenImResponseDTO;
import com.fs.im.service.OpenIMService;
import com.fs.qw.domain.CustomerTransferApproval;
import com.fs.qw.dto.FsUserTransferParamDTO;
import com.fs.qw.dto.UserProjectDTO;
import com.fs.qw.service.ICustomerTransferApprovalService;
import com.fs.store.param.h5.FsUserPageListParam;
import com.fs.user.param.FsUserRedStatusParam;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.fs.his.utils.PhoneUtil.encryptPhone;

@Api(tags = "会员管理接口")
@RestController
@Slf4j
@RequestMapping("/user/fsUser")
@AllArgsConstructor
public class FsUserAdminController extends BaseController {

    @Autowired
    private IFsUserService fsUserService;

    @Autowired
    private ICompanyUserCacheService companyUserCacheService;

    @Autowired
    private ICompanyUserService companyUserService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ICustomerTransferApprovalService transferApprovalService;

    @Autowired
    private IFsUserCourseService fsUserCourseService;

    @Autowired
    private OpenIMService openIMService;

    @Autowired
    private IFsUserCompanyUserService fsUserCompanyUserService;

    @Autowired
    private FsUserCompanyUserMapper fsUserCompanyUserMapper;

    @Autowired
    private FsCourseWatchLogMapper fsCourseWatchLogMapper;

    @Autowired
    private IFsUserCoursePeriodService fsUserCoursePeriodService;

    @PreAuthorize("@ss.hasPermi('user:fsUser:list')")
    @PostMapping("/list")
    @ApiOperation("会员列表(与移动端使用的相同查询)")
    public TableDataInfo pageList(@RequestBody FsUserPageListParam param) {
        //startPage();

        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
       /* if (param.getIsMyFsUser()){
            param.setCompanyId(loginUser.getCompany().getCompanyId());
            param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
        }else {
            param.setCompanyId(loginUser.getCompany().getCompanyId());
        }*/
        param.setCompanyId(loginUser.getCompany().getCompanyId());
        if(param.getPhone()!=null && !"".equals(param.getPhone())){
            param.setPhone(PhoneUtil.encryptPhone(param.getPhone()));
        }
//        if(param.getCompanyUserId() == null) {
//            throw new IllegalArgumentException("当前销售不存在！");
//        }
        return fsUserService.selectFsUserPageListNew(param);
    }

    @PreAuthorize("@ss.hasPermi('user:fsUser:myList')")
    @PostMapping("/myList")
    @ApiOperation("我的会员列表(与移动端使用的相同查询)")
    public TableDataInfo pageMyList(@RequestBody FsUserPageListParam param) {

        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        param.setCompanyId(loginUser.getCompany().getCompanyId());
        param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
        param.setIsAdmin(loginUser.getUser().isAdmin());

        if(param.getCompanyUserId() == null) {
            throw new IllegalArgumentException("当前销售不存在！");
        }
        return fsUserService.selectFsUserPageListNew(param);
    }

    @PostMapping("/auditUser")
    @ApiOperation("审核用户（移除小黑屋）")
    public R auditUser(@RequestBody String[] userIds) {
        Boolean r = fsUserService.disabledUser(userIds, true);
        if (r) {
            return R.ok();
        }
        return R.error();
    }

    /**
     * 转移
     * @param param
     */
    @PostMapping("/transfer")
    public R transfer(@RequestBody FsUserTransferParamDTO param){
        log.info("客户转移: {}",param);
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        param.setSourceCompanyUserId(loginUser.getUser().getUserId());
        CustomerTransferApproval customerTransferApproval = new CustomerTransferApproval();
        customerTransferApproval.setCorpId(String.valueOf(loginUser.getCompany().getCompanyId()));
        customerTransferApproval.setCustomerIds(JSON.toJSONString(param.getUserIds()));
        customerTransferApproval.setOriginalUserId(param.getSourceCompanyUserId());
        customerTransferApproval.setTargetUserId(param.getTargetCompanyUserId());
        customerTransferApproval.setInitiatorUserId(param.getSourceCompanyUserId());
        customerTransferApproval.setContent(param.getContent());
        customerTransferApproval.setCreatedAt(new Date());
        customerTransferApproval.setUpdatedAt(new Date());
        customerTransferApproval.setApprovalStatus(0);
        customerTransferApproval.setTransferType(2);
        transferApprovalService.insertCustomerTransferApproval(customerTransferApproval);
        return R.ok("转移申请已经提交，等待转移成功!");
    }

    /**
     * 获取用户详细信息
     */
    @GetMapping(value = "/{userId}")
    public AjaxResult getInfo(@PathVariable("userId") Long userId)
    {
        return AjaxResult.success(fsUserService.selectFsUserPageListVOByUserId(userId));
    }

    /**
     * 获取项目用户详细信息
     */
    @GetMapping(value = "/member/{id}")
    public AjaxResult getMemberInfo(@PathVariable("id") Long id)
    {
        return AjaxResult.success(fsUserService.selectFsMemberUserPageListVOById(id));
    }

    /**
     * 修改用户
     */
//    @PreAuthorize("@ss.hasPermi('user:fsUser:edit')")
    @Log(title = "用户", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody FsUser fsUser)
    {
        return toAjax(fsUserService.updateFsUser(fsUser));
    }

    /**
     * 修改用户
     */
    @PreAuthorize("@ss.hasPermi('user:fsUser:edit')")
    @Log(title = "用户", businessType = BusinessType.UPDATE)
    @PutMapping("/member")
    public AjaxResult editMemberUser(@RequestBody FsUserCompanyUser fsUser)
    {
        return toAjax(fsUserCompanyUserService.updateFsUserCompanyUser(fsUser));
    }

    @PreAuthorize("@ss.hasPermi('user:fsUser:edit')")
    @Log(title = "会员红包领取开关", businessType = BusinessType.UPDATE)
    @PutMapping("/redStatus")
    @ApiOperation("修改会员红包领取开关（red_status：1开启 0关闭）")
    public AjaxResult updateRedStatus(@Valid @RequestBody FsUserRedStatusParam param) {
        FsUser fsUser = fsUserService.selectFsUserById(param.getUserId());
        if (fsUser == null) {
            return AjaxResult.error("用户不存在");
        }
        FsUser update = new FsUser();
        update.setUserId(param.getUserId());
        update.setRedStatus(param.getRedStatus());
        return toAjax(fsUserService.updateFsUser(update));
    }

    @ApiOperation("后台会员批量发送课程消息")
    @PostMapping("/batchSendCourse")
    public OpenImResponseDTO batchSendCourse(@RequestBody BatchSendCourseDTO batchSendCourseDTO) throws JsonProcessingException {
        // 生成看课短链
        FsCourseLinkCreateParam fsCourseLinkCreateParam = new FsCourseLinkCreateParam();
        BeanUtils.copyProperties(batchSendCourseDTO, fsCourseLinkCreateParam);
        R courseSortLink = fsUserCourseService.createAppCourseSortLink(fsCourseLinkCreateParam);
        String url = courseSortLink.get("url").toString();
        batchSendCourseDTO.setUrl(url);
        batchSendCourseDTO.setIsUrgeCourse(false);
        return openIMService.batchSendCourse(batchSendCourseDTO);
    }

    /**
     * 获取会员营期转移的下拉框数据
     * 包括：当前公司下的营期列表和销售列表
     *
     * @return 营期列表和销售列表
     */
    @GetMapping("/getPeriodTransferOptions")
    @ApiOperation("获取会员营期转移下拉框数据")
    public R getPeriodTransferOptions() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        Long companyId = loginUser.getCompany().getCompanyId();

        // 查询当前公司下的营期列表
        FsUserCoursePeriod periodQuery = new FsUserCoursePeriod();
        periodQuery.setCompanyId(companyId.toString());
        List<FsUserCoursePeriod> periodList = fsUserCoursePeriodService.selectFsUserCoursePeriodList(periodQuery);

        // 查询当前公司下的销售列表
        CompanyUser userQuery = new CompanyUser();
        userQuery.setCompanyId(companyId);
        List<CompanyUser> companyUserList = companyUserService.selectCompanyUserList(userQuery);

        return R.ok()
                .put("periodList", periodList)
                .put("companyUserList", companyUserList);
    }

    /**
     * 加载指定源营期和源销售下的会员列表
     * 用于会员营期转移功能中选择需要转移的会员
     *
     * @param sourcePeriodId 源营期ID
     * @param sourceCompanyUserId 源销售ID
     * @return 会员列表
     */
    @GetMapping("/loadPeriodUserList")
    @ApiOperation("加载指定源营期和源销售下的会员列表")
    public R loadPeriodUserList(@RequestParam Long sourcePeriodId,
                                @RequestParam Long sourceCompanyUserId) {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        Long companyId = loginUser.getCompany().getCompanyId();

        try {
            // 1. 验证营期是否存在且属于当前公司
            FsUserCoursePeriod period = fsUserCoursePeriodService.selectFsUserCoursePeriodById(sourcePeriodId);
            if (period == null) {
                return R.error("营期不存在");
            }
            if (!period.getCompanyId().contains(companyId.toString())) {
                return R.error("营期不属于当前公司");
            }

            // 2. 验证销售是否存在且属于当前公司
            CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(sourceCompanyUserId);
            if (companyUser == null) {
                return R.error("销售不存在");
            }
            if (!companyUser.getCompanyId().equals(companyId)) {
                return R.error("销售不属于当前公司");
            }

            // 3. 查询该营期和销售下的会员ID列表
            List<Long> userIds = fsUserCompanyUserMapper
                    .selectUserIdsByPeriodIdAndCompanyUserId(sourcePeriodId, sourceCompanyUserId, companyId);

            log.info("查询营期ID:{}, 销售ID:{} 下的会员数量：{}",
                    sourcePeriodId, sourceCompanyUserId, userIds.size());

            // 4. 查询会员详细信息
            List<Map<String, Object>> userList = new ArrayList<>();
            for (Long userId : userIds) {
                FsUser fsUser = fsUserService.selectFsUserById(userId);
                if (fsUser != null && fsUser.getIsDel() == 0) {
                    Map<String, Object> userInfo = new HashMap<>();
                    userInfo.put("userId", fsUser.getUserId());
                    userInfo.put("nickName", fsUser.getNickName());
                    userInfo.put("phone", fsUser.getPhone());
                    userInfo.put("avatar", fsUser.getAvatar());
                    userInfo.put("createTime", fsUser.getCreateTime());
                    userList.add(userInfo);
                }
            }

            return R.ok()
                    .put("total", userList.size())
                    .put("userList", userList);

        } catch (Exception e) {
            log.error("加载会员列表失败", e);
            return R.error("加载会员列表失败：" + e.getMessage());
        }
    }

    /**
     * 会员营期转移
     * 功能：将从源营期的某个销售下的会员，转移到目标营期的某个销售下
     * 例如：香江0808某销售下的会员 需要转到 百脳1002期内的某个销售下
     *
     * @param param 转移参数
     * @return 结果
     */
    @PreAuthorize("@ss.hasPermi('user:fsUser:periodTransfer')")
    @Log(title = "会员营期转移", businessType = BusinessType.UPDATE)
    @PostMapping("/periodTransfer")
    @ApiOperation("会员营期转移")
    public R periodTransfer(@RequestBody PeriodUserTransferParam param) {
        log.info("会员营期转移请求：{}", JSON.toJSONString(param));

        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        Long companyId = loginUser.getCompany().getCompanyId();
        Long currentUserId = loginUser.getUser().getUserId();

        try {
            // 1. 参数校验
            if (param.getUserIds() == null || param.getUserIds().isEmpty()) {
                return R.error("请选择需要转移的会员");
            }

            // 2. 验证源营期和目标营期是否存在
            FsUserCoursePeriod sourcePeriod = fsUserCoursePeriodService.selectFsUserCoursePeriodById(param.getSourcePeriodId());
            if (sourcePeriod == null) {
                return R.error("源营期不存在");
            }

            FsUserCoursePeriod targetPeriod = fsUserCoursePeriodService.selectFsUserCoursePeriodById(param.getTargetPeriodId());
            if (targetPeriod == null) {
                return R.error("目标营期不存在");
            }

            // 3. 验证营期归属公司
            if (!sourcePeriod.getCompanyId().contains(companyId.toString())) {
                return R.error("源营期不属于当前公司");
            }

            if (!targetPeriod.getCompanyId().contains(companyId.toString())) {
                return R.error("目标营期不属于当前公司");
            }

            // 4. 验证销售是否存在
            CompanyUser sourceCompanyUser = companyUserCacheService.selectCompanyUserById(param.getSourceCompanyUserId());
            if (sourceCompanyUser == null) {
                return R.error("源销售不存在");
            }

            CompanyUser targetCompanyUser = companyUserCacheService.selectCompanyUserById(param.getTargetCompanyUserId());
            if (targetCompanyUser == null) {
                return R.error("目标销售不存在");
            }

            if (!companyId.equals(sourceCompanyUser.getCompanyId())) {
                return R.error("源销售不属于当前公司");
            }

            if (!companyId.equals(targetCompanyUser.getCompanyId())) {
                return R.error("目标销售不属于当前公司");
            }

            // 5. 批量转移会员营期关系
            int successCount = 0;
            int failCount = 0;
            StringBuilder failReasons = new StringBuilder();
            List<UserProjectDTO> userProjectList = new ArrayList<>();

            // 先查询源营期和源销售下的所有有效会员ID（通过观看记录表关联）
            List<Long> validUserIds = fsUserCompanyUserMapper
                    .selectUserIdsByPeriodIdAndCompanyUserId(
                            param.getSourcePeriodId(), param.getSourceCompanyUserId(), companyId);

            log.info("源营期ID:{}, 源销售ID:{} 下查询到有效会员数：{}",
                    param.getSourcePeriodId(), param.getSourceCompanyUserId(), validUserIds.size());

            for (Long userId : param.getUserIds()) {
                try {
                    // 验证会员是否在源营期和源销售下
                    if (!validUserIds.contains(userId)) {
                        failReasons.append("会员ID:").append(userId).append("在源营期和源销售下不存在; ");
                        failCount++;
                        continue;
                    }

                    // 从观看记录获取该营期下关联的项目ID（project_id 存的是项目ID，不是营期ID）
                    List<Long> projectIds = fsCourseWatchLogMapper.selectProjectIdsByUserPeriodAndCompanyUser(
                            userId, param.getSourcePeriodId(), param.getSourceCompanyUserId(), companyId);
                    if (projectIds.isEmpty()) {
                        FsUserCompanyUser queryParam = new FsUserCompanyUser();
                        queryParam.setUserId(userId);
                        queryParam.setCompanyUserId(param.getSourceCompanyUserId());
                        queryParam.setCompanyId(companyId);
                        projectIds = fsUserCompanyUserService.selectFsUserCompanyUserList(queryParam).stream()
                                .map(FsUserCompanyUser::getProjectId)
                                .filter(Objects::nonNull)
                                .distinct()
                                .collect(Collectors.toList());
                    }
                    if (projectIds.isEmpty()) {
                        failReasons.append("会员ID:").append(userId).append("未找到可转移的项目关系; ");
                        failCount++;
                        continue;
                    }

                    // 更新会员-项目-销售关系：保持项目ID不变，仅变更销售
                    for (Long projectId : projectIds) {
                        fsUserCompanyUserService.changeRelationship(
                                userId, projectId, companyId, param.getTargetCompanyUserId());
                        log.info("更新会员项目销售关系 - 会员ID:{}, 项目ID:{}, 源销售ID:{}, 目标销售ID:{}",
                                userId, projectId, param.getSourceCompanyUserId(), param.getTargetCompanyUserId());
                    }

                    // 更新观看记录中的营期和销售
                    int watchLogCount = fsCourseWatchLogMapper.transferPeriodWatchLog(
                            userId, param.getSourcePeriodId(), param.getSourceCompanyUserId(),
                            param.getTargetPeriodId(), param.getTargetCompanyUserId(), companyId);
                    log.info("更新观看记录 - 会员ID:{}, 源营期ID:{}, 目标营期ID:{}, 更新条数:{}",
                            userId, param.getSourcePeriodId(), param.getTargetPeriodId(), watchLogCount);

                    // 仅当会员主归属属于当前公司时，更新fs_user表
                    FsUser fsUser = fsUserService.selectFsUserById(userId);
                    if (fsUser != null && Objects.equals(fsUser.getCompanyId(), companyId)) {
                        fsUser.setCompanyUserId(param.getTargetCompanyUserId());
                        fsUserService.updateFsUser(fsUser);
                        log.info("更新fs_user表 - 会员ID:{}, 公司ID:{}, 销售ID:{}",
                                userId, companyId, param.getTargetCompanyUserId());
                    }

                    for (Long projectId : projectIds) {
                        UserProjectDTO dto = new UserProjectDTO();
                        dto.setUserId(userId);
                        dto.setProjectId(projectId);
                        userProjectList.add(dto);
                    }

                    successCount++;
                    log.info("会员ID:{} 从营期ID:{} 销售ID:{} 转移到 营期ID:{} 销售ID:{} 成功",
                            userId, param.getSourcePeriodId(), param.getSourceCompanyUserId(),
                            param.getTargetPeriodId(), param.getTargetCompanyUserId());

                } catch (Exception e) {
                    log.error("会员ID:{} 转移失败", userId, e);
                    failReasons.append("会员ID:").append(userId).append("转移失败:").append(e.getMessage()).append("; ");
                    failCount++;
                }
            }

            // 6. 创建审批记录并记录到审批列表

            CustomerTransferApproval approval = new CustomerTransferApproval();
            approval.setCorpId(String.valueOf(companyId));
            approval.setTransferType(3); // 3=会员营期转移
            approval.setCustomerIds(JSON.toJSONString(userProjectList));
            approval.setCustomerList(null); // 避免自动反序列化错误
            approval.setOriginalUserId(param.getSourceCompanyUserId());
            approval.setTargetUserId(param.getTargetCompanyUserId());
            approval.setInitiatorUserId(currentUserId);


            // 根据转移结果设置审批状态
            if (successCount > 0 && failCount == 0) {
                // 全部成功，自动审批通过
                approval.setApprovalStatus(1);
                approval.setApprovalRemark("会员营期转移成功");
            } else if (successCount == 0 && failCount > 0) {
                // 全部失败，审批驳回
                approval.setApprovalStatus(2);
                approval.setApprovalRemark("会员营期转移全部失败：" + failReasons.toString());
            } else {
                // 部分成功，设为待审批状态供管理员查看
                approval.setApprovalStatus(0);
                approval.setApprovalRemark(String.format("部分成功，成功%d人，失败%d人。失败原因：%s",
                    successCount, failCount, failReasons.toString()));
            }
            approval.setContent(param.getReason()); // 转移原因
            approval.setApproverUserId(currentUserId);
            approval.setProcessedAt(new Date());
            approval.setCreatedAt(new Date());
            approval.setUpdatedAt(new Date());

            // 保存审批记录
            transferApprovalService.insertCustomerTransferApproval(approval);
            log.info("会员营期转移审批记录已创建，审批ID：{}", approval.getId());

            // 7. 返回结果
            String resultMsg = String.format("转移完成！成功:%d人，失败:%d人", successCount, failCount);
            if (failCount > 0) {
                resultMsg += ". 失败原因：" + failReasons.toString();
            }

            log.info("会员营期转移结果：{}", resultMsg);
            return R.ok(resultMsg)
                    .put("successCount", successCount)
                    .put("failCount", failCount)
                    .put("approvalId", approval.getId());

        } catch (Exception e) {
            log.error("会员营期转移异常", e);
            return R.error("会员营期转移失败：" + e.getMessage());
        }
    }

    /**
     * 解绑会员
     * @param ids
     * @return
     */
    @DeleteMapping("/{ids}")
    public R editUser(@PathVariable String[] ids) {
        return fsUserCompanyUserService.deleFsUserCompanyUserByIds(ids);
    }

    @PreAuthorize("@ss.hasPermi('his:user:unbind')")
    @Log(title = "批量解绑会员（删除销售和会员的关系）", businessType = BusinessType.DELETE)
    @DeleteMapping("/batchUnbind")
    public AjaxResult batchUnbind(@RequestBody List<Long> userIds){
        if(!userIds.isEmpty()){
            return toAjax(fsUserCompanyUserService.batchUnbind(userIds));
        } else {
            return error("请先选择会员");
        }
    }
}
