package com.bcxin.tenant.open.domains.services.impls;

import com.bcxin.tenant.open.document.domains.documents.RdCompanyDocument;
import com.bcxin.tenant.open.document.domains.documents.RdDispatchDataScopeDocument;
import com.bcxin.tenant.open.document.domains.documents.RdSecurityStationDocument;
import com.bcxin.tenant.open.document.domains.repositories.RdCompanyDocumentRepository;
import com.bcxin.tenant.open.document.domains.repositories.RdDispatchDataScopeDocumentRepository;
import com.bcxin.tenant.open.document.domains.repositories.RdSecurityStationDocumentRepository;
import com.bcxin.tenant.open.domains.entities.RdSecurityStationEntity;
import com.bcxin.tenant.open.domains.entities.StationDeviceEntity;
import com.bcxin.tenant.open.domains.readers.RdCompositedReader;
import com.bcxin.tenant.open.domains.repositories.RdSecurityStationRepository;
import com.bcxin.tenant.open.domains.repositories.StationDeviceRepository;
import com.bcxin.tenant.open.domains.services.SecurityStationService;
import com.bcxin.tenant.open.domains.services.commands.CreateSyncStationCommand;
import com.bcxin.tenant.open.domains.services.commands.RefreshStationCountOfSecurityManCommand;
import com.bcxin.tenant.open.domains.utils.RdSecurityStationEntityUtil;
import com.bcxin.tenant.open.infrastructures.UnitWork;
import com.bcxin.tenant.open.infrastructures.components.JsonProvider;
import com.bcxin.tenant.open.infrastructures.exceptions.BadTenantException;
import com.redis.om.spring.search.stream.EntityStream;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class SecurityStationServiceImpl implements SecurityStationService {
    private final RdSecurityStationRepository stationRepository;
    private final UnitWork unitWork;
    private final JsonProvider jsonProvider;
    private final RdCompositedReader compositedReader;
    private final RdSecurityStationDocumentRepository securityStationDocumentRepository;
    private final RdDispatchDataScopeDocumentRepository dispatchDataScopeDocumentRepository;
    private final RdCompanyDocumentRepository companyDocumentRepository;
    private final EntityStream entityStream;
    private final StationDeviceRepository stationDeviceRepository;

    public SecurityStationServiceImpl(RdSecurityStationRepository stationRepository,
                                      UnitWork unitWork,
                                      JsonProvider jsonProvider,
                                      RdCompositedReader compositedReader,
                                      RdSecurityStationDocumentRepository securityStationDocumentRepository,
                                      RdDispatchDataScopeDocumentRepository dispatchDataScopeDocumentRepository,
                                      RdCompanyDocumentRepository companyDocumentRepository, EntityStream entityStream, StationDeviceRepository stationDeviceRepository) {
        this.stationRepository = stationRepository;
        this.unitWork = unitWork;
        this.jsonProvider = jsonProvider;
        this.compositedReader = compositedReader;
        this.securityStationDocumentRepository = securityStationDocumentRepository;
        this.dispatchDataScopeDocumentRepository = dispatchDataScopeDocumentRepository;
        this.companyDocumentRepository = companyDocumentRepository;
        this.entityStream = entityStream;
        this.stationDeviceRepository = stationDeviceRepository;
    }

    @Override
    public void dispatch(RefreshStationCountOfSecurityManCommand command) {
        String tranId = this.unitWork.beginTransaction();
        try {
            this.stationRepository.updateCountOfSecurityMen(command.getStationIds());
            this.unitWork.commit(tranId);
        } catch (Exception ex) {
            this.unitWork.rollback(tranId);
            throw ex;
        }
    }

    @Override
    public void dispatch(CreateSyncStationCommand command) {
        String tranId = this.unitWork.beginTransaction();
        try {
            RdSecurityStationEntity stationEntity = this.jsonProvider.toObject(RdSecurityStationEntity.class, command.getContent());
            if (stationEntity == null) {
                throw new BadTenantException(String.format("无效数据格式:%s", command.getContent()));
            }

            Collection<RdDispatchDataScopeDocument> dataScopeDocuments = new ArrayList<>();
            Collection<RdCompanyDocument> proprietorCompanyDocuments = new ArrayList<>();

            RdDispatchDataScopeDocument dataScopeDocument =
                    dispatchDataScopeDocumentRepository.findById(stationEntity.getId()).orElse(null);
            if (dataScopeDocument != null) {
                dataScopeDocuments.add(dataScopeDocument);
                proprietorCompanyDocuments = this.companyDocumentRepository.findAllById(dataScopeDocument.getScopes());
            }

            Collection<StationDeviceEntity> stationDevices =
                    this.stationDeviceRepository.getByStationIds(
                            Stream.of(stationEntity.getId()).collect(Collectors.toList())
                    );

            RdSecurityStationDocument document =
                    RdSecurityStationEntityUtil.toDocument(stationEntity, true,
                            securityStationDocumentRepository, this.entityStream,
                            dataScopeDocuments, proprietorCompanyDocuments, stationDevices);
            if (document == null) {
                throw new BadTenantException(String.format("驻勤点-数据库解析异常:id=%s;name=%s;", stationEntity.getId(), stationEntity.getName()));
            }

            this.securityStationDocumentRepository.save(document);

            if (this.stationRepository.getByNoPkId(stationEntity.getId()) != null) {
                this.stationRepository.update(stationEntity);
            } else {
                this.stationRepository.insert(stationEntity);
            }

            this.unitWork.commit(tranId);
        } catch (Exception ex) {
            this.unitWork.rollback(tranId);
            throw ex;
        }
    }
}
