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

import com.bcxin.tenant.open.document.domains.documents.RdSecurityStationDocument;
import com.bcxin.tenant.open.document.domains.documents.RdSecurityStationDocument$;
import com.bcxin.tenant.open.domains.dtos.PoliceIncidentsSosUpdateDTO;
import com.bcxin.tenant.open.domains.entities.PoliceIncidentsEntity;
import com.bcxin.tenant.open.domains.entities.valueTypes.GeoPointValueType;
import com.bcxin.tenant.open.domains.repositories.PoliceIncidentsRepository;
import com.bcxin.tenant.open.domains.services.PoliceIncidentsService;
import com.bcxin.tenant.open.domains.services.UserPurseService;
import com.bcxin.tenant.open.domains.services.commands.*;
import com.bcxin.tenant.open.infrastructures.TenantContext;
import com.bcxin.tenant.open.infrastructures.TenantEmployeeContext;
import com.bcxin.tenant.open.infrastructures.UnitWork;
import com.bcxin.tenant.open.infrastructures.components.IdWorker;
import com.bcxin.tenant.open.infrastructures.components.JsonProvider;
import com.bcxin.tenant.open.infrastructures.constants.BusinessConstants;
import com.bcxin.tenant.open.infrastructures.enums.PoliceEventStatus;
import com.bcxin.tenant.open.infrastructures.enums.ResourceType;
import com.bcxin.tenant.open.infrastructures.enums.UserPurseTransactionType;
import com.bcxin.tenant.open.infrastructures.exceptions.BadTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.ForbidTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.NoFoundTenantException;
import com.bcxin.tenant.open.infrastructures.exceptions.UnAuthorizedTenantException;
import com.bcxin.tenant.open.infrastructures.utils.BusinessUtil;
import com.bcxin.tenant.open.infrastructures.utils.PoliceEventCategoryUtils;
import com.redis.om.spring.search.stream.EntityStream;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *  警情上报
 */
@Service
public class PoliceIncidentsServiceImpl implements PoliceIncidentsService {
    private final JsonProvider jsonProvider;
    private final UnitWork unitWork;
    private final PoliceIncidentsRepository policeIncidentsRepository;
    private final EntityStream entityStream;
    private final IdWorker idWorker;

    private final UserPurseService userPurseService;

    public PoliceIncidentsServiceImpl(JsonProvider jsonProvider, UnitWork unitWork,
                                      PoliceIncidentsRepository policeIncidentsRepository,
                                      EntityStream entityStream, IdWorker idWorker, UserPurseService userPurseService) {
        this.jsonProvider = jsonProvider;
        this.unitWork = unitWork;
        this.policeIncidentsRepository = policeIncidentsRepository;
        this.entityStream = entityStream;
        this.idWorker = idWorker;
        this.userPurseService = userPurseService;
    }

    @Override
    public void dispatch(CreatePoliceIncidentsCommand command) {
        TenantEmployeeContext.TenantUserModel userModel = TenantContext.getInstance().getUserContext().get();
        if (userModel == null) {
            throw new UnAuthorizedTenantException();
        }

        if (BusinessUtil.checkIfDesk(userModel.getAccountType())) {
            throw new BadTenantException("调度台账号, 不允许进行警情上报");
        }

        String securityStationId = BusinessConstants.DefaultEmptyValue;
        String securityStationName = BusinessConstants.DefaultEmptyValue;
        String securityStationAddress = null;
        String superviseDepartId = userModel.getSuperviseDepartId();

        String projectId = BusinessConstants.DefaultEmptyValue;
        String projectName = "";

        Set<ResourceType> resourceTypes = new HashSet<>();
        resourceTypes.add(ResourceType.Security);

        if (BusinessUtil.checkIfSecurityStationRelativeUsers(userModel.getOrgInstitutional())) {
            securityStationId = userModel.getSecurityStationId();

            boolean hasSecurityStation = false;
            if (StringUtils.hasLength(securityStationId) && !BusinessConstants.DefaultEmptyValue.equalsIgnoreCase(securityStationId)) {
                RdSecurityStationDocument securityStationDocument =
                        entityStream.of(RdSecurityStationDocument.class)
                                .filter(RdSecurityStationDocument$.ID.eq(securityStationId)).findFirst().orElse(null);

                if (securityStationDocument != null) {
                    hasSecurityStation = true;
                    securityStationName = securityStationDocument.getName();
                    securityStationAddress = securityStationDocument.getAddress();
                    projectName = securityStationDocument.getProjectName();
                    projectId = securityStationDocument.getProjectId();

                    resourceTypes.clear();
                    resourceTypes = ResourceType.toResourceTypes(securityStationDocument.getResourceTypes());
                }
            }

            if (!StringUtils.hasLength(projectId)) {
                projectId = BusinessConstants.DefaultEmptyValue;
            }

            if (!hasSecurityStation) {
                throw new BadTenantException("未安排驻勤点的保安人员, 不允许进行警情上报");
            }
        }

        if (!StringUtils.hasLength(superviseDepartId)) {
            superviseDepartId = BusinessConstants.DefaultEmptyValue;
        }

        String tranId = this.unitWork.beginTransaction();
        try {
            PoliceIncidentsEntity policeIncident = new PoliceIncidentsEntity();
            String code = String.valueOf(this.idWorker.getNextId());
            policeIncident.setCode(code);
            policeIncident.setAddress(command.getAddress());
            policeIncident.setContact(command.getContact());
            policeIncident.setEmpName(userModel.getName());
            policeIncident.setLonLat(GeoPointValueType.create(command.getLatitude(), command.getLongitude()));
            policeIncident.setName(command.getName());
            policeIncident.setSecurityStationId(securityStationId);
            policeIncident.setSecurityStationName(securityStationName);
            policeIncident.setSecurityStationAddress(securityStationAddress);

            policeIncident.setSuperviseDepartId(superviseDepartId);
            policeIncident.setTenantEmployeeId(userModel.getEmployeeId());
            policeIncident.setTenantUserId(userModel.getTencentUserId());
            policeIncident.setCategory(command.getCategory());
            /**
             * 上报的位置
             */
            policeIncident.setLocation(command.getLocation());

            policeIncident.setPoliceEventStatus(PoliceEventStatus.None);
            policeIncident.setPoliceEventLevel(command.getPoliceEventLevel());
            policeIncident.setPoliceEventType(command.getPoliceEventType());
            policeIncident.setOrganizationId(userModel.getOrganizationId());
            policeIncident.setOrganizationName(userModel.getOrgName());
            policeIncident.setReason(command.getReason());
            policeIncident.setSceneUrl(command.getSceneUrl());
            policeIncident.setActionTaken(command.getActionTaken());
            policeIncident.setActionTendency(command.getActionTendency());
            policeIncident.setDescription(command.getDescription());
            policeIncident.changeExtends(jsonProvider, command.getItems());

            if (BusinessConstants.DefaultEmptyValue.equalsIgnoreCase(policeIncident.getSuperviseDepartName())) {
                policeIncident.setSuperviseDepartName(" ");
            }
            if (BusinessConstants.DefaultEmptyValue.equalsIgnoreCase(policeIncident.getSecurityStationName())) {
                policeIncident.setSecurityStationName(" ");
            }

            int calculatedResourceType = ResourceType.getCalculatedResourceValue(resourceTypes);

            if (calculatedResourceType < 1) {
                calculatedResourceType = 1;
            }

            policeIncident.setCalculatedResourceType(calculatedResourceType);
            policeIncident.setProjectId(projectId);
            policeIncident.setProjectName(projectName);

            policeIncident.setTypeName(PoliceEventCategoryUtils.getEventTypeName(
                    policeIncident.getCategory(),
                    policeIncident.getPoliceEventType()
            ));

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

    @Override
    public void dispatch(UpdatePoliceIncidentsCommand command) {
        TenantEmployeeContext.TenantUserModel userModel = TenantContext.getInstance().getUserContext().get();
        if (userModel == null) {
            throw new UnAuthorizedTenantException();
        }

        PoliceIncidentsEntity policeIncident = policeIncidentsRepository.getById(command.getId());
        if (policeIncident == null) {
            throw new NoFoundTenantException();
        }

        String tranId = this.unitWork.beginTransaction();
        try {
            policeIncident.process(
                    userModel.getEmployeeId(), userModel.getName(),
                    command.getPoliceEventStatus(), command.getActionTaken(),
                    command.getActionTendency(), command.getProcessedSuggestion(),
                    command.getProcessedLocaleGuidance(),
                    command.getPoints()
            );

            policeIncidentsRepository.update(policeIncident);

            CreateUserPurseTransactionCommand.CreateUserPurseTransactionsCommand purseCommand =
                    CreateUserPurseTransactionCommand.CreateUserPurseTransactionsCommand.create(
                            Stream.of(
                                    CreateUserPurseTransactionCommand.create(
                                            UserPurseTransactionType.PoliceIncident,
                                            String.valueOf(policeIncident.getId()),
                                            policeIncident.getTenantUserId(),
                                            policeIncident.getReason(),
                                            command.getPoints()
                                    )
                            ).collect(Collectors.toList())
                    );
            this.userPurseService.dispatch(purseCommand);

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

            throw ex;
        }
    }

    @Override
    public void dispatch(UpdatePoliceIncidentStatusCommand command) {
        TenantEmployeeContext.TenantUserModel userModel = TenantContext.getInstance().getUserContext().get();
        if(userModel==null) {
            throw new UnAuthorizedTenantException();
        }

        PoliceIncidentsEntity policeIncident =
                policeIncidentsRepository.getById(command.getId());
        if (policeIncident == null) {
            throw new NoFoundTenantException();
        }

        String tranId = this.unitWork.beginTransaction();
        try {
            policeIncident.makeAsOverStatus(userModel.getEmployeeId(),userModel.getName(),command.getStatus());
            this.policeIncidentsRepository.update(policeIncident);
            this.unitWork.commit(tranId);
        } catch (Exception ex) {
            this.unitWork.rollback(tranId);

            throw ex;
        }
    }

    @Override
    public void dispatch(Collection<CreateSsoPoliceIncidentsCommand> commands) {
        this.unitWork.executeTran(() -> {
            commands.forEach(command -> {
                String code = String.valueOf(this.idWorker.getNextId());
                PoliceIncidentsEntity entity =
                        PoliceIncidentsEntity.createSos
                                (
                                        jsonProvider,
                                        code,
                                        command.getTenantUserId(),
                                        command.getTenantEmployeeId(),
                                        command.getOrganizationId(),
                                        command.getOrganizationName(),
                                        command.getSecurityStationId(),
                                        command.getSecurityStationName(),
                                        command.getProjectId(),
                                        command.getProjectName(),
                                        command.getStationAddress(),
                                        command.getSuperviseDepartId(),
                                        command.getSuperviseDepartName(),
                                        command.getTenantUserIdCard(),
                                        command.getTenantUserName(),
                                        command.getLatitude(),
                                        command.getLongitude(),
                                        command.getAddress(),
                                        command.getResourceTypes()
                                );

                this.policeIncidentsRepository.insert(entity);
            });
        });
    }

    @Override
    public void dispatch(UpdateSosPoliceIncidentStatusCommand command) {
        this.unitWork.executeTran(() -> {
            this.policeIncidentsRepository.updateSsoStatus(
                    PoliceIncidentsSosUpdateDTO.create(command.getId(),
                            command.getProcessorId(),
                            command.getProcessedUserName())
            );
        });
    }

    @Override
    public void dispatch(UpdatePoliceIncidentsInfoCommand command) {
        TenantEmployeeContext.TenantUserModel userModel = TenantContext.getInstance().getUserContext().get();
        if(userModel==null) {
            throw new UnAuthorizedTenantException();
        }

        PoliceIncidentsEntity policeIncident =
                policeIncidentsRepository.getById(command.getId());
        if (policeIncident == null) {
            throw new NoFoundTenantException();
        }

        String tranId = this.unitWork.beginTransaction();
        try {
            policeIncident.change(command.getSceneUrl(),command.getDescription());
            this.policeIncidentsRepository.update(policeIncident);
            this.unitWork.commit(tranId);
        } catch (Exception ex) {
            this.unitWork.rollback(tranId);

            throw ex;
        }
    }

    @Override
    public void delete(Long id) {
        TenantEmployeeContext.TenantUserModel userModel = TenantContext.getInstance().getUserContext().get();
        if (userModel == null) {
            throw new UnAuthorizedTenantException();
        }

        PoliceIncidentsEntity policeIncident =
                policeIncidentsRepository.getById(id);
        if (policeIncident == null) {
            throw new NoFoundTenantException();
        }

        /*
        if (!userModel.getEmployeeId().equalsIgnoreCase(policeIncident.getTenantEmployeeId())) {
            throw new ForbidTenantException("非本人不允许删除其他人的数据信息");
        }

        if (policeIncident.getPoliceEventStatus() != PoliceEventStatus.None) {
            throw new ForbidTenantException("不允许删除处理中的数据");
        }
         */

        this.unitWork.executeTran(() -> {
            this.policeIncidentsRepository.delete(policeIncident);
        });
    }
}
