package cn.skcks.docking.gb28181.wvp.service.catalog;

import cn.skcks.docking.gb28181.common.xml.XmlUtils;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
import cn.skcks.docking.gb28181.core.sip.message.subscribe.GenericSubscribe;
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
import cn.skcks.docking.gb28181.wvp.orm.mybatis.dynamic.model.WvpProxyDocking;
import cn.skcks.docking.gb28181.wvp.service.docking.DockingService;
import cn.skcks.docking.gb28181.wvp.sip.message.message.catalog.dto.CatalogRequestDTO;
import cn.skcks.docking.gb28181.wvp.sip.message.message.catalog.dto.CatalogResponseDTO;
import cn.skcks.docking.gb28181.wvp.sip.request.SipRequestBuilder;
import cn.skcks.docking.gb28181.wvp.sip.sender.SipSender;
import cn.skcks.docking.gb28181.wvp.sip.subscribe.SipSubscribe;
import gov.nist.javax.sip.message.SIPRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.sip.message.Request;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Service
@RequiredArgsConstructor
public class CatalogService {
    private final SipSender sipSender;
    private final SipSubscribe sipSubscribe;
    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    private final DockingService dockingService;

    public void getCatalog(String deviceId){
        WvpProxyDocking device = dockingService.getDeviceByDeviceCode(deviceId).orElse(null);
        if (device == null){
            throw new RuntimeException("设备不存在");
        }
        CatalogRequestDTO catalogRequestDTO = new CatalogRequestDTO();
        catalogRequestDTO.setDeviceId(deviceId);
        String sn = String.valueOf((int) (Math.random() * 9 + 1) * 100000);
        catalogRequestDTO.setSn(sn);
        String key = GenericSubscribe.Helper.getKey(Request.MESSAGE, deviceId);
        sipSubscribe.getCatalogSubscribe().addPublisher(key);
        final ScheduledFuture<?>[] schedule = new ScheduledFuture<?>[1];
        Flow.Subscriber<SIPRequest> subscriber = catalog(key, device, schedule);
        // 60秒超时计时器
        schedule[0] = scheduledExecutorService.schedule(subscriber::onComplete, 60 , TimeUnit.SECONDS);
        sipSender.sendRequest((provider, ip, port)-> SipRequestBuilder.createMessageRequest(device,ip,port,1L, XmlUtils.toXml(catalogRequestDTO), SipUtil.generateViaTag(),
                SipUtil.generateFromTag(), provider.getNewCallId()));
    }

    private Flow.Subscriber<SIPRequest> catalog(String key, WvpProxyDocking device, ScheduledFuture<?>[] schedule){
        return new Flow.Subscriber<>() {
            Flow.Subscription subscription;

            final AtomicLong getNum = new AtomicLong(0);

            @Override
            public void onSubscribe(Flow.Subscription subscription) {
                log.info("创建 订阅 {}", key);
                this.subscription = subscription;
                subscription.request(1);
            }

            @Override
            public void onNext(SIPRequest item) {
                CatalogResponseDTO responseDTO = XmlUtils.parse(item.getRawContent(), CatalogResponseDTO.class, GB28181Constant.CHARSET);
                Long sumNum = responseDTO.getSumNum();
                log.info("{}",responseDTO);
                getNum.getAndAdd(responseDTO.getDeviceList().getDeviceList().size());
                if(getNum.get() < sumNum){
                    subscription.request(1);
                } else{
                    onComplete();
                }
            }

            @Override
            public void onError(Throwable throwable) {
                onComplete();
            }

            @Override
            public void onComplete() {
                sipSubscribe.getCatalogSubscribe().delPublisher(key);
                schedule[0].cancel(true);
            }
        };
    }
}
