package cn.axzo.msg.center.nimpush.device;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

import cn.axzo.epic.client.common.enums.AppTerminalTypeEnum;
import cn.axzo.epic.client.feign.AppDeviceApi;
import cn.axzo.epic.client.vo.request.BatchFetchDeviceByPersonIdAndTerminalReq;
import cn.axzo.epic.client.vo.response.ApkDeviceMaxCodeResp;
import cn.axzo.msg.center.common.enums.SystemTypeEnum;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.inside.notices.config.push.PushDeviceVersion;
import cn.axzo.msg.center.nimpush.PushChannel;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author yanglin
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PushDeviceService {

    private final AppDeviceApi appDeviceApi;
    private final PendingMessageBizConfig cfg;

    public PushDevice getDevice(long personId) {
        return createDeviceSnapshots(Collections.singletonList(personId)).getDevice(personId);
    }

    public PushDeviceSnapshots createDeviceSnapshots(Collection<Long> personIds) {
        if (CollectionUtils.isNotEmpty(personIds))
            return new PushDeviceSnapshots(this, Collections.emptyList());
        ArrayList<Long> uniquePersonIds = new ArrayList<>(new HashSet<>(personIds));
        BatchFetchDeviceByPersonIdAndTerminalReq request = new BatchFetchDeviceByPersonIdAndTerminalReq();
        request.setPersonIds(uniquePersonIds);
        request.setTerminals(Arrays.asList(
                AppTerminalTypeEnum.CMP, AppTerminalTypeEnum.CM));
        List<ApkDeviceMaxCodeResp> devices = BizAssertions.assertResponse(
                appDeviceApi.batchfetchCodeByPersonIdAndTerminal(request));
        return new PushDeviceSnapshots(this, devices);
    }

    boolean shouldPush(PushTerminalEnum pushTerminal,
                       PushChannel pushChannel,
                       List<ApkDeviceMaxCodeResp> devices) {
        Supplier<Boolean> ambiguity = () -> {
            Set<PushChannel> channels = cfg
                    .getPushChannels().getAmbiguityPushChannels();
            return channels.contains(pushChannel);
        };
        if (CollectionUtils.isEmpty(devices))
            return ambiguity.get();
        if (devices.size() > 2)
            log.warn("Person has more than 2 latest login devices. personId={}, devices={}",
                    devices.get(0).getPersonId(), JSON.toJSONString(devices));
        AppTerminalTypeEnum terminalType = null;
        if (pushTerminal == PushTerminalEnum.B_ENTERPRISE_APP)
            terminalType = AppTerminalTypeEnum.CMP;
        else if (pushTerminal == PushTerminalEnum.C_WORKER_APP)
            terminalType = AppTerminalTypeEnum.CM;
        if (terminalType == null)
            return ambiguity.get();
        Integer configuredVersion = null;
        int deviceVersion = 0;
        for (ApkDeviceMaxCodeResp device : devices) {
            if (device.getTerminal() != terminalType)
                continue;
            SystemTypeEnum systemType = convertEpicSystemType(device.getSystemType());
            if (systemType == null)
                return ambiguity.get();
            PushDeviceVersion nimPushVersion = cfg
                    .getPushChannels().getNimPushVersion(systemType);
            if (nimPushVersion == null)
                return ambiguity.get();
            if (terminalType == AppTerminalTypeEnum.CM)
                configuredVersion = nimPushVersion.getWorkerAppVersion();
            if (terminalType == AppTerminalTypeEnum.CMP)
                configuredVersion = nimPushVersion.getManagerAppVersion();
            deviceVersion = device.getCode();
        }
        if (configuredVersion == null || configuredVersion <= 0 || deviceVersion <= 0)
            return ambiguity.get();

        // 分开写, 好理解一些
        if (pushChannel == PushChannel.NIM)
            return deviceVersion >= configuredVersion;
        if (pushChannel == PushChannel.YOU_MENG)
            return deviceVersion < configuredVersion;
        // should never happen
        return ambiguity.get();
    }

    private static SystemTypeEnum convertEpicSystemType(
            cn.axzo.epic.client.common.enums.SystemTypeEnum systemType) {
        if (systemType == cn.axzo.epic.client.common.enums.SystemTypeEnum.ANDROID)
            return SystemTypeEnum.ANDROID;
        if (systemType == cn.axzo.epic.client.common.enums.SystemTypeEnum.IOS)
            return SystemTypeEnum.IOS;
        return null;
    }
}