package com.zsElectric.boot.business.service.impl;

import com.zsElectric.boot.business.mapper.FirmAccountLogMapper;
import com.zsElectric.boot.business.model.entity.FirmAccountLog;
import com.zsElectric.boot.business.model.form.FirmBalanceChangeForm;
import com.zsElectric.boot.core.exception.BusinessException;
import com.zsElectric.boot.common.model.Option;
import com.zsElectric.boot.security.util.SecurityUtils;
import com.zsElectric.boot.system.service.DeptService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsElectric.boot.business.mapper.FirmInfoMapper;
import com.zsElectric.boot.business.service.FirmInfoService;
import com.zsElectric.boot.business.model.entity.FirmInfo;
import com.zsElectric.boot.business.model.form.FirmInfoForm;
import com.zsElectric.boot.business.model.query.FirmInfoQuery;
import com.zsElectric.boot.business.model.vo.FirmInfoVO;
import com.zsElectric.boot.business.converter.FirmInfoConverter;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.collection.CollectionUtil;

/**
 * 企业信息服务实现类
 *
 * @author zsElectric
 * @since 2025-12-11 10:10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FirmInfoServiceImpl extends ServiceImpl<FirmInfoMapper, FirmInfo> implements FirmInfoService {

    /**
     * 三方用户角色编码
     */
    private static final String ROLE_SFUSER = "SFUSER";

    private final FirmInfoConverter firmInfoConverter;
    private final FirmAccountLogMapper firmAccountLogMapper;
    private final DeptService deptService;

    /**
    * 获取企业信息分页列表
    *
    * @param queryParams 查询参数
    * @return {@link IPage<FirmInfoVO>} 企业信息分页列表
    */
    @Override
    public IPage<FirmInfoVO> getFirmInfoPage(FirmInfoQuery queryParams) {
        // 判断当前用户是否为三方用户，如果是则只查询自己所属公司的数据
        Set<String> roles = SecurityUtils.getRoles();
        if (roles != null && roles.contains(ROLE_SFUSER)) {
            // 三方用户只能查询自己所属部门的企业数据
            Long deptId = SecurityUtils.getDeptId();
            queryParams.setDeptId(deptId);
        }
        Page<FirmInfoVO> pageVO = this.baseMapper.getFirmInfoPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );
        return pageVO;
    }
    
    /**
     * 获取企业信息表单数据
     *
     * @param id 企业信息ID
     * @return 企业信息表单数据
     */
    @Override
    public FirmInfoForm getFirmInfoFormData(Long id) {
        FirmInfo entity = this.getById(id);
        return firmInfoConverter.toForm(entity);
    }
    
    /**
     * 新增企业信息
     *
     * @param formData 企业信息表单对象
     * @return 是否新增成功
     */
    @Override
    public boolean saveFirmInfo(FirmInfoForm formData) {
        FirmInfo entity = firmInfoConverter.toEntity(formData);
        return this.save(entity);
    }
    
    /**
     * 更新企业信息
     *
     * @param id   企业信息ID
     * @param formData 企业信息表单对象
     * @return 是否修改成功
     */
    @Override
    public boolean updateFirmInfo(Long id,FirmInfoForm formData) {
        FirmInfo entity = firmInfoConverter.toEntity(formData);
        return this.updateById(entity);
    }
    
    /**
     * 删除企业信息
     *
     * @param ids 企业信息ID，多个以英文逗号(,)分割
     * @return 是否删除成功
     */
    @Override
    public boolean deleteFirmInfos(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的企业信息数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        return this.removeByIds(idList);
    }

    /**
     * 上账（充值）- 增加企业余额
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean recharge(Long firmId, BigDecimal amount, String remark) {
        FirmBalanceChangeForm form = new FirmBalanceChangeForm();
        form.setFirmId(firmId);
        form.setAmount(amount);
        form.setIncomeType(1); // 转入
        form.setChangeType(1); // 充值
        form.setRemark(remark);
        return changeBalance(form);
    }

    /**
     * 下账（扣款）- 减少企业余额
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deduct(Long firmId, BigDecimal amount, String remark) {
        FirmBalanceChangeForm form = new FirmBalanceChangeForm();
        form.setFirmId(firmId);
        form.setAmount(amount);
        form.setIncomeType(2); // 转出
        form.setChangeType(2); // 提现/扣款
        form.setRemark(remark);
        return changeBalance(form);
    }

    /**
     * 企业账户余额变更
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeBalance(FirmBalanceChangeForm form) {
        // 1. 查询企业信息
        FirmInfo firmInfo = this.getById(form.getFirmId());
        if (firmInfo == null) {
            throw new BusinessException("企业不存在");
        }

        // 2. 计算变更前余额
        BigDecimal beforeBalance = firmInfo.getBalance() != null ? firmInfo.getBalance() : BigDecimal.ZERO;
        BigDecimal changeAmount = form.getAmount();
        BigDecimal afterBalance;

        // 3. 根据收支类型计算变更后余额
        if (form.getIncomeType() == 1) {
            // 上账/转入
            afterBalance = beforeBalance.add(changeAmount);
            // 更新累计充值
            BigDecimal totalRecharge = firmInfo.getTotalRecharge() != null ? firmInfo.getTotalRecharge() : BigDecimal.ZERO;
            firmInfo.setTotalRecharge(totalRecharge.add(changeAmount));
        } else {
            // 下账/转出
            if (beforeBalance.compareTo(changeAmount) < 0) {
                throw new BusinessException("企业余额不足");
            }
            afterBalance = beforeBalance.subtract(changeAmount);
        }

        // 4. 更新企业余额
        firmInfo.setBalance(afterBalance);
        this.updateById(firmInfo);

        // 5. 记录资金流水
        FirmAccountLog accountLog = new FirmAccountLog();
        accountLog.setFirmId(form.getFirmId());
        accountLog.setFirmType(firmInfo.getFirmType()); // 设置类型（1-企业 2-渠道）
        accountLog.setProjectName("企业账户");
        accountLog.setName(form.getIncomeType() == 1 ? "上账" : "下账");
        accountLog.setSerialNo(generateSerialNo());
        accountLog.setIncomeType(form.getIncomeType());
        accountLog.setBeforeChange(beforeBalance);
        accountLog.setAfterChange(afterBalance);
        accountLog.setMoneyChange(changeAmount);
        accountLog.setChangeType(form.getChangeType() != null ? form.getChangeType() : (form.getIncomeType() == 1 ? 1 : 2));
        accountLog.setRemark(form.getRemark());
        accountLog.setCreateTime(LocalDateTime.now());
        firmAccountLogMapper.insert(accountLog);

        log.info("企业账户余额变更成功 - firmId: {}, incomeType: {}, amount: {}, before: {}, after: {}",
                form.getFirmId(), form.getIncomeType(), changeAmount, beforeBalance, afterBalance);

        return true;
    }

    /**
     * 生成流水号
     */
    private String generateSerialNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase();
        return "FIRM" + timestamp + uuid;
    }

    /**
     * 获取可用的部门选项（排除已被企业/渠道使用的部门）
     *
     * @param excludeId 编辑时排除的企业ID（允许选择自己关联的部门）
     * @return 可用部门选项列表
     */
    @Override
    public List<Option<Long>> getAvailableDeptOptions(Long excludeId) {
        // 1. 获取所有已被使用的deptId
        LambdaQueryWrapper<FirmInfo> queryWrapper = new LambdaQueryWrapper<FirmInfo>()
                .select(FirmInfo::getDeptId)
                .isNotNull(FirmInfo::getDeptId);
        // 如果是编辑模式，排除当前企业自己
        if (excludeId != null) {
            queryWrapper.ne(FirmInfo::getId, excludeId);
        }
        List<FirmInfo> usedFirmList = this.list(queryWrapper);
        Set<Long> usedDeptIds = usedFirmList.stream()
                .map(FirmInfo::getDeptId)
                .collect(Collectors.toSet());

        // 2. 获取所有部门选项
        List<Option<Long>> allDeptOptions = deptService.listDeptOptions();

        // 3. 提取子部门（排除顶级部门parent_id=0）
        List<Option<Long>> childDeptOptions = new ArrayList<>();
        for (Option<Long> option : allDeptOptions) {
            if (CollectionUtil.isNotEmpty(option.getChildren())) {
                childDeptOptions.addAll(option.getChildren());
            }
        }

        // 4. 过滤掉已被使用的部门
        return filterAvailableOptions(childDeptOptions, usedDeptIds);
    }

    /**
     * 递归过滤可用的部门选项
     */
    private List<Option<Long>> filterAvailableOptions(List<Option<Long>> options, Set<Long> usedDeptIds) {
        if (CollectionUtil.isEmpty(options)) {
            return options;
        }
        return options.stream()
                .filter(option -> !usedDeptIds.contains(option.getValue()))
                .peek(option -> {
                    if (CollectionUtil.isNotEmpty(option.getChildren())) {
                        option.setChildren(filterAvailableOptions(option.getChildren(), usedDeptIds));
                    }
                })
                .collect(Collectors.toList());
    }

    /**
     * 根据部门ID获取企业ID
     *
     * @param deptId 部门ID
     * @return 企业ID，如果不存在则返回null
     */
    @Override
    public Long getFirmIdByDeptId(Long deptId) {
        if (deptId == null) {
            return null;
        }
        LambdaQueryWrapper<FirmInfo> queryWrapper = new LambdaQueryWrapper<FirmInfo>()
                .select(FirmInfo::getId)
                .eq(FirmInfo::getDeptId, deptId)
                .last("LIMIT 1");
        FirmInfo firmInfo = this.getOne(queryWrapper);
        return firmInfo != null ? firmInfo.getId() : null;
    }
}
