package org.wfc.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.wfc.common.core.constant.WifiConstants;
import org.wfc.common.core.domain.LoginUser;
import org.wfc.common.core.utils.ResponseUtils;
import org.wfc.common.security.utils.SecurityUtils;
import org.wfc.omada.api.client.OmadaClientApi;
import org.wfc.omada.api.client.OmadaClientInsightApi;
import org.wfc.omada.api.client.model.ClientHistoryInfo;
import org.wfc.omada.api.client.model.ClientInfo;
import org.wfc.omada.api.client.model.OperationResponseClientGridVoClientInfo;
import org.wfc.omada.api.client.model.OperationResponseGridVoClientHistoryInfo;
import org.wfc.omada.api.device.OmadaDeviceApi;
import org.wfc.omada.api.device.model.DeviceInfo;
import org.wfc.omada.api.device.model.OperationResponseGridVoDeviceInfo;
import org.wfc.omada.api.organization.OmadaSiteApi;
import org.wfc.omada.api.organization.model.OperationResponseGridVoSiteSummaryInfo;
import org.wfc.omada.api.organization.model.SiteSummaryInfo;
import org.wfc.user.api.IWifiApi;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UCdr;
import org.wfc.user.domain.UCdrHistory;
import org.wfc.user.domain.UClient;
import org.wfc.user.domain.UDevice;
import org.wfc.user.domain.bo.UCdrClientBo;
import org.wfc.user.domain.bo.UUCdrHistoryUserBo;
import org.wfc.user.domain.constant.UserTypeEnum;
import org.wfc.user.domain.vo.UCdrClientVo;
import org.wfc.user.domain.vo.UCdrHistoryUserVo;
import org.wfc.user.domain.vo.UCdrUserVo;
import org.wfc.user.mapper.UCdrMapper;
import org.wfc.user.service.IUAccountService;
import org.wfc.user.service.IUCdrHistoryService;
import org.wfc.user.service.IUCdrService;
import org.wfc.user.service.IUClientService;
import org.wfc.user.service.IUDeviceService;
import org.wfc.user.util.AccountUtil;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户平台_用户话单表 服务实现类
 * </p>
 *
 * @author cyc
 * @since 2024-12-09
 */
@Service
public class UCdrServiceImpl extends ServiceImpl<UCdrMapper, UCdr> implements IUCdrService {

    @Autowired
    private OmadaSiteApi omadaSiteApi;

    @Autowired
    private OmadaDeviceApi omadaDeviceApi;

    @Autowired
    private OmadaClientApi omadaClientApi;

    @Autowired
    private OmadaClientInsightApi omadaClientInsightApi;

    @Autowired
    private IUDeviceService deviceService;

    @Autowired
    private IUClientService clientService;

    @Autowired
    private IUCdrHistoryService cdrHistoryService;

    @Autowired
    private IUAccountService accountService;

    @Autowired
    private IWifiApi wifiApi;

    @Autowired
    private IUClientService uClientService;


    @Override
    public UCdrUserVo getByUser() {
        LoginUser<Object> loginUser = SecurityUtils.getLoginUser();
        List<UCdrUserVo> cdrUsers = this.baseMapper.getByUser(loginUser.getUserid(), null, null);
        return cdrUsers.stream().findFirst().orElse(null);
    }

    @Override
    public List<UCdrClientVo> getByClient(UCdrClientBo client) {
        return this.baseMapper.getByClient(client);
    }

    @Override
    public List<UCdrHistoryUserVo> getHistoryByUser(UUCdrHistoryUserBo item) {
        LoginUser<Object> loginUser = SecurityUtils.getLoginUser();
        item.setUserId(loginUser.getUserid());
        return this.baseMapper.getHistoryByUser(item);
    }

    @Override
    public void addCdrInfoByOmadaApi() {
        ResponseEntity<OperationResponseGridVoSiteSummaryInfo> siteResp = omadaSiteApi.getSiteList(1, 1000);
        if (ObjectUtil.isNull(siteResp.getBody())) {
            return;
        }
        if (!ResponseUtils.isSuccessResponse(siteResp.getBody().getErrorCode(), siteResp.getBody().getMsg())) {
            return;
        }
        List<SiteSummaryInfo> sites = siteResp.getBody().getResult().getData();
        List<UClient> allClients = clientService.list(Wrappers.<UClient>lambdaQuery().isNotNull(UClient::getUserId));
        // 添加AP设备
        addDevices(sites);
        for (SiteSummaryInfo site : sites) {
            ResponseEntity<OperationResponseClientGridVoClientInfo> clientResp = omadaClientApi.getGridActiveClients(site.getSiteId(), 1, 1000);
            if (ObjectUtil.isNull(clientResp.getBody())) {
                continue;
            }
            List<ClientInfo> clients = clientResp.getBody().getResult().getData();
            // 授权client
            List<String> macs = authClients(clients);

            // 新增cdr历史
            for (UClient client : allClients) {
                if (!Objects.equals(client.getSiteId(), site.getSiteId())) {
                    continue;
                }
                UCdr uCdr = this.getOne(Wrappers.<UCdr>lambdaQuery().eq(UCdr::getUserId, client.getUserId())
                        .eq(UCdr::getClientId, client.getId()), false);
                if (ObjectUtil.isNotNull(uCdr)) {
                    addCdrHistory(site.getSiteId(), client.getClientMac(), uCdr.getId());
                }
            }

            // 根据返回授权成功的clients, 加上当前状态是已授权的clients
            clients = clients.stream().filter(c -> WifiConstants.AUTH_STATUS_AUTHORIZED == c.getAuthStatus() || macs.contains(c.getMac()))
                    .collect(Collectors.toList());
            List<Long> activeIds = new ArrayList<>();
            for (ClientInfo client : clients) {
                // 添加用户设备
                UClient hasClient = addClient(client, site.getSiteId());
                // 添加话单
                addCdr(client, hasClient);
                // 记录使用类型(当前生效套餐或余额)
                recordUseType(hasClient);
                activeIds.add(hasClient.getId());
            }
            // 根据返回已active的client ids, 更新非这些ids的active为false
            List<UClient> unActiveClients = allClients.stream().filter(c -> site.getSiteId().equals(c.getSiteId())
                    && !activeIds.contains(c.getId())).map(c -> {
                UClient client = new UClient();
                client.setId(c.getId());
                client.setActive(false);
                return client;
            }).collect(Collectors.toList());
            clientService.updateBatchById(unActiveClients);
        }
        // 统计和取消授权
        accountService.statAndCancelAuthUser();
    }

    private List<String> authClients(List<ClientInfo> clients) {
        List<String> macs = new ArrayList<>();
        List<String> clientMacs = clients.stream().filter(c -> ObjectUtil.isNotNull(c.getAuthStatus()) && c.getAuthStatus() != 2)
                .map(ClientInfo::getMac).collect(Collectors.toList());
        if (CollUtil.isEmpty(clientMacs)) {
            return macs;
        }
        List<UClient> unAuthClients = clientService.list(Wrappers.<UClient>lambdaQuery().isNotNull(UClient::getUserId).in(UClient::getClientMac, clientMacs));
        List<Long> userIds = unAuthClients.stream().map(UClient::getUserId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return macs;
        }
        List<UAccount> accounts = accountService.list(Wrappers.<UAccount>lambdaQuery().in(UAccount::getUserId, userIds));
        for (UClient unAuthClient : unAuthClients) {
            for (UAccount account : accounts) {
                if (Objects.equals(unAuthClient.getUserId(), account.getUserId())) {
                    if (AccountUtil.isValid(account, new Date())) {
                        if (account.getClientNumEnable()) {
                            int onlineClientNum = uClientService.getCurrentClients(account.getUserId()).size();
                            if (onlineClientNum >= account.getClientNum()) {
                                continue;
                            }
                        }
                        // 授权成功返回，以及考虑是否reconnect，截出pending部分
                        boolean authFlag = wifiApi.authClient(unAuthClient.getSiteId(), unAuthClient.getClientMac());
                        if (!authFlag) {
                            macs.add(unAuthClient.getClientMac());
                        }
                    }
                }
            }

        }
        return macs;
    }

    private void addCdrHistory(String siteId, String mac, Long cdrId) {
        // 话单历史
        // 时间戳范围，取当前时间一天前到现在的范围
        ResponseEntity<OperationResponseGridVoClientHistoryInfo> pastConnResp = omadaClientInsightApi.getGridPastConnections(siteId, 1, 1000, "asc",DateUtil.yesterday().getTime() + "", System.currentTimeMillis() + "", mac);
        if (ObjectUtil.isNull(pastConnResp.getBody())) {
            return;
        }
        List<ClientHistoryInfo> pastConns = pastConnResp.getBody().getResult().getData();
        for (ClientHistoryInfo pastConn : pastConns) {
            UCdrHistory hasCdrHistory = cdrHistoryService.getOne(Wrappers.<UCdrHistory>lambdaQuery().eq(UCdrHistory::getCdrId, cdrId).eq(UCdrHistory::getStartTime, pastConn.getFirstSeen()), false);
            if (ObjectUtil.isNotNull(hasCdrHistory)) {
                continue;
            }

            UCdrHistory uCdrHistory = UCdrHistory.builder().cdrId(cdrId).startTime(pastConn.getFirstSeen())
                    .endTime(pastConn.getLastSeen())
                    .trafficUp(pastConn.getUpload())
                    .trafficDown(pastConn.getDownload())
                    .duration(pastConn.getDuration())
                    .build();

            // 将在线的client时查出的使用类型(套餐或余额)记录到历史数据中
            UClient client = this.baseMapper.getClientByFirstSeen(siteId, mac, pastConn.getFirstSeen());
            if (client != null) {
                uCdrHistory.setUseType(client.getUseType());
                if (UserTypeEnum.PACKAGE.getCode().equals(client.getUseType())) {
                    uCdrHistory.setUseId(client.getUseId());
                }
            }

            cdrHistoryService.save(uCdrHistory);

            if (client != null) {
                // 如果是余额类型，更新当前账户的余额，并且生成一个bill账单
                if (UserTypeEnum.BALANCE.getCode().equals(client.getUseType())) {
                    accountService.generateBill(client.getUserId(), uCdrHistory.getId());
                }
            }
        }
    }

    private Long addCdr(ClientInfo client, UClient hasClient) {
        // 话单
        UCdr hasUCdr = this.getOne(Wrappers.<UCdr>lambdaQuery()
                .eq(ObjectUtil.isNotNull(hasClient.getUserId()), UCdr::getUserId, hasClient.getUserId())
                .eq(UCdr::getClientId, hasClient.getId()), false);
        Long cdrId = null;
        if (ObjectUtil.isNotNull(hasUCdr)) {
            cdrId = hasUCdr.getId();
        }
        UDevice hasDevice = deviceService.getOne(Wrappers.<UDevice>lambdaQuery().eq(UDevice::getDeviceMac, client.getApMac()), false);
        UCdr uCdr = UCdr.builder().clientId(hasClient.getId())
                .userId(hasClient.getUserId())
                .deviceId(hasDevice.getId())
                .ssid(client.getSsid())
                .rxRate(client.getRxRate())
                .txRate(client.getTxRate())
                .lastSeenTime(client.getLastSeen())
                .upTime(client.getUptime())
                .upPacket(client.getUpPacket())
                .downPacket(client.getDownPacket())
                .trafficDown(client.getTrafficDown())
                .trafficUp(client.getTrafficUp())
                .activity(client.getActivity())
                .build();
        uCdr.setId(cdrId);
        this.saveOrUpdate(uCdr);
        return uCdr.getId();
    }

    private UClient addClient(ClientInfo client, String siteId) {
        // 用户设备
        UClient hasClient = clientService.getOne(Wrappers.<UClient>lambdaQuery().eq(UClient::getSiteId, siteId)
                .eq(UClient::getClientMac, client.getMac()), false);
        Long clientId = null;
        Long userId = null;
        if (ObjectUtil.isNotNull(hasClient)) {
            clientId = hasClient.getId();
            userId = hasClient.getUserId();
        }
        UClient uClient = UClient.builder().clientMac(client.getMac())
                .siteId(siteId)
                .userId(userId)
                .clientName(client.getName())
                .clientDeviceType(client.getDeviceType())
                .build();
        uClient.setId(clientId);

        clientService.saveOrUpdate(uClient);
        return uClient;
    }

    private void recordUseType(UClient uClient) {
        // 更新active为true，查当前use是否有account，account是否有套餐或余额，记录当前使用的是套餐还是余额
        uClient.setActive(true);
        Long userId = uClient.getUserId();
        if (userId != null) {
            UAccount account = accountService.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, userId), false);
            if (AccountUtil.isPackageValidNoUsedBalance(account, new Date())) {
                uClient.setUseType(UserTypeEnum.PACKAGE.getCode());
                uClient.setUseId(account.getPackageId());
            } else if (AccountUtil.isBalanceValid(account)) {
                uClient.setUseType(UserTypeEnum.BALANCE.getCode());
            } else {
                uClient.setUseType(UserTypeEnum.OTHER.getCode());
            }
        }
        clientService.updateById(uClient);
    }

    private void addDevices(List<SiteSummaryInfo> sites) {
        // ap设备
        for (SiteSummaryInfo site : sites) {
            ResponseEntity<OperationResponseGridVoDeviceInfo> deviceResp = omadaDeviceApi.getDeviceList(site.getSiteId(), 1, 1000);
            if (ObjectUtil.isNull(deviceResp.getBody())) {
                return;
            }
            List<DeviceInfo> devices = deviceResp.getBody().getResult().getData();
            for (DeviceInfo device : devices) {
                UDevice hasUDevice = deviceService.getOne(Wrappers.<UDevice>lambdaQuery().eq(UDevice::getDeviceMac, device.getMac()), false);
                if (ObjectUtil.isNotNull(hasUDevice)) {
                    continue;
                }
                UDevice uDevice = UDevice.builder().deviceIp(device.getIp())
                        .deviceMac(device.getMac())
                        .deviceName(device.getName())
                        .deviceModel(device.getModel())
                        .build();
                deviceService.save(uDevice);
            }
        }
    }

}
