package org.wfc.user.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.wfc.common.core.exception.ServiceException;
import org.wfc.common.security.utils.SecurityUtils;
import org.wfc.user.api.IWifiApi;
import org.wfc.user.api.omada.domain.convert.OmadaConvert;
import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UAccountPackage;
import org.wfc.user.domain.UBill;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.domain.UClient;
import org.wfc.user.domain.UOrder;
import org.wfc.user.domain.UPackage;
import org.wfc.user.domain.URateLimit;
import org.wfc.user.domain.constant.OrderStatusEnum;
import org.wfc.user.domain.constant.OrderTypeEnum;
import org.wfc.user.domain.constant.PeriodTypeEnum;
import org.wfc.user.mapper.UAccountPackageMapper;
import org.wfc.user.mapper.UBillMapper;
import org.wfc.user.mapper.UBillRuleMapper;
import org.wfc.user.mapper.UOrderMapper;
import org.wfc.user.service.IUAccountService;
import org.wfc.user.service.IUClientService;
import org.wfc.user.service.IUOrderService;
import org.wfc.user.service.IUPackageService;
import org.wfc.user.service.IURateLimitService;
import org.wfc.user.util.AccountUtil;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 用户平台-订单表 服务实现类
 * </p>
 *
 * @author sys
 * @since 2024-12-20
 */
@Service
public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> implements IUOrderService {

    @Autowired
    private IUPackageService packageService;

    @Autowired
    private IURateLimitService rateLimitService;

    @Autowired
    private IUAccountService accountService;

    @Autowired
    private IUClientService clientService;

    @Autowired
    private UBillMapper billMapper;

    @Autowired
    private UBillRuleMapper billRuleMapper;

    @Autowired
    private UAccountPackageMapper accountPackageMapper;

    @Autowired
    private IWifiApi wifiApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean paySuccess(Long orderId) {
        // 支付成功回调
        // 更新当前订单状态为已支付
        UOrder order = this.getById(orderId);
        if (OrderStatusEnum.PAID.getCode().equals(order.getStatus())) {
            return false;
        }
        order.setStatus(OrderStatusEnum.PAID.getCode());
        this.updateById(order);

        // 保存账单信息
        UBill bill = new UBill();
        bill.setAmount(order.getOrderAmount());
        bill.setUserId(order.getUserId());
        bill.setType(order.getType());
        bill.setStatus(OrderStatusEnum.PAID.getCode());
        billMapper.insert(bill);

        // 保存或更新账户信息
        UAccount account = accountService.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, order.getUserId()), false);
        Long accountId = null;
        boolean isValid = false;
        BigDecimal oldBalance = BigDecimal.ZERO;
        if (ObjectUtil.isNull(account)) {
            account = new UAccount();
            account.setUserId(order.getUserId());
            account.setBalance(BigDecimal.ZERO);
            account.setBalanceUsed(BigDecimal.ZERO);
        } else {
            accountId = account.getId();
            oldBalance = account.getBalance();
            isValid = AccountUtil.isValid(account, new Date());
        }
        if (OrderTypeEnum.PACKAGE.getCode().equals(order.getType())) {
            // 套餐
            callbackPackage(order, account, false);
        } else if (OrderTypeEnum.RECHARGE.getCode().equals(order.getType())) {
            // 充值
            // 更新账户余额
            account.setBalance(order.getOrderAmount().add(Optional.ofNullable(account.getBalance()).orElse(BigDecimal.ZERO)));
            // 如果已欠费，充值时补充欠费部分以抵消
            if (ObjectUtil.isNull(account.getBalanceUsed()) && account.getBalanceUsed().compareTo(BigDecimal.ZERO) > 0
                    && ObjectUtil.isNull(account.getBalance()) && account.getBalance().subtract(account.getBalanceUsed()).compareTo(BigDecimal.ZERO) < 0) {
                account.setBalance(account.getBalance().add(account.getBalanceUsed().subtract(account.getBalance())));
            }

        }
        account.setId(accountId);

        accountService.saveOrUpdate(account);

        // 授权当前用户的所有设备访问wifi
        List<UClient> clients = clientService.list(Wrappers.<UClient>lambdaQuery().eq(UClient::getUserId, order.getUserId()));
        for (UClient client : clients) {
            if (StrUtil.isNotBlank(client.getSiteId())) {
                wifiApi.authClient(client.getSiteId(), client.getClientMac());
                // 套餐生效已授权时，调reconnect重连接口，以便截取时间
                if (isValid && !(OrderTypeEnum.RECHARGE.getCode().equals(order.getType()) && oldBalance.compareTo(BigDecimal.ZERO) > 0)) {
                    wifiApi.reconnectClient(client.getSiteId(), client.getClientMac());
                }
                // 带宽限速
                ClientRateLimitSettingDto clientRateLimitSetting = OmadaConvert.INSTANCE.toClientRateLimitSettingDto(account);
                wifiApi.updateClientRateLimitSetting(client.getSiteId(), client.getClientMac(), clientRateLimitSetting);
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean payByBalance(Long orderId) {
        UOrder order = this.getById(orderId);
        if (!OrderTypeEnum.PACKAGE.getCode().equals(order.getType())) {
            throw new ServiceException("user.order.pay.type.error");
        }
        UAccount account = accountService.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, order.getUserId()), false);

        BigDecimal balance;
        if (ObjectUtil.isNull(account)) {
            throw new ServiceException("user.order.pay.amount.error");
        } else {
            account.setBalance(Optional.ofNullable(account.getBalance()).orElse(BigDecimal.ZERO));
            balance = account.getBalance().subtract(Optional.ofNullable(account.getBalanceUsed()).orElse(BigDecimal.ZERO));
        }
        if (order.getOrderAmount().compareTo(balance) > 0) {
            throw new ServiceException("user.order.pay.amount.error");
        }
        if (paySuccess(orderId)) {
            UAccount updateAccount = new UAccount();
            updateAccount.setId(account.getId());
            updateAccount.setBalance(account.getBalance().subtract(order.getOrderAmount()));
            accountService.updateById(updateAccount);
        }

        return true;
    }

    private void callbackPackage(UOrder order, UAccount account, boolean isValid) {
        if (ObjectUtil.isNull(order.getPackageId())) {
            return;
        }
        UAccountPackage accountPackage = new UAccountPackage();

        UPackage uPackage = packageService.getById(order.getPackageId());
        Boolean rateLimitEnable = uPackage.getRateLimitEnable();
        rateLimitEnable = ObjectUtil.isNotNull(uPackage.getRateLimitId()) ? rateLimitEnable : false;
        if (rateLimitEnable) {
            URateLimit rateLimit = rateLimitService.getById(uPackage.getRateLimitId());
            if (isValid) {
                BeanUtils.copyProperties(rateLimit, accountPackage);
            } else {
                BeanUtils.copyProperties(rateLimit, account);
            }
        }

        if (isValid) {
            BeanUtils.copyProperties(uPackage, accountPackage);
            accountPackage.setPackageId(order.getPackageId());
            accountPackageMapper.insert(accountPackage);
        } else {
            BeanUtils.copyProperties(uPackage, account);
            account.setPackageId(order.getPackageId());
            account.setTrafficUsed(0L);
            account.setDurationUsed(0L);
            account.setClientNumUsed(0);
            Date current = new Date();
            DateTime endTime = getEndTime(uPackage, current);
            account.setStartTime(current);
            account.setEndTime(endTime);
        }
    }

    private static DateTime getEndTime(UPackage uPackage, Date current) {
        DateTime endTime = null;
        // 计算有效时间
        switch (PeriodTypeEnum.getByCode(uPackage.getPeriodType())) {
            case HOUR:
                endTime = DateUtil.offset(current, DateField.HOUR, uPackage.getPeriodNum());
                break;
            case DAY:
                endTime = DateUtil.offset(current, DateField.DAY_OF_YEAR, uPackage.getPeriodNum());
                break;
            case MONTH:
                endTime = DateUtil.offset(current, DateField.MONTH, uPackage.getPeriodNum());
                break;
            case YEAR:
                endTime = DateUtil.offset(current, DateField.YEAR, uPackage.getPeriodNum());
                break;
            default:
        }
        return endTime;
    }

    @Override
    public Long saveOrder(UOrder order) {
        order.setUserId(SecurityUtils.getUserId());
        order.setStatus(OrderStatusEnum.UNPAID.getCode());
        order.setOrderNo(System.currentTimeMillis() + StrUtil.EMPTY);
        if (ObjectUtil.isNotNull(order.getPackageId())) {
            UPackage uPackage = packageService.getById(order.getPackageId());
            order.setOrderAmount(uPackage.getPrice());
        }
        this.save(order);
        List<UBillRule> billRules = billRuleMapper.selectList(Wrappers.lambdaQuery());
        billRules.stream().findFirst().ifPresent(billRule -> {
            // 测试
            if (billRule.getTraffic() == 1) {
                // 支付成功回调
//                paySuccess(order.getId());
            }
        });

        return order.getId();
    }
}
