package com.yuchen.saas.park.service.service.door.config.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yuchen.saas.park.api.commons.PageWrapper;
import com.yuchen.saas.park.api.commons.domain.*;
import com.yuchen.saas.park.api.dto.door.DoorAccessControlConfigSettingDTO;
import com.yuchen.saas.park.api.entity.door.config.DoorAccessControlUserPermissions;
import com.yuchen.saas.park.service.mapper.domain.DoorAccessControlBlacklistedCondition;
import com.yuchen.saas.park.service.mapper.domain.DoorAccessControlBlacklistedRO;
import com.yuchen.saas.park.service.mapper.door.card.DoorAccessControlCardBiometricsRepository;
import com.yuchen.saas.park.service.mapper.door.card.DoorAccessControlCardRepository;
import com.yuchen.saas.park.service.mapper.door.config.DoorAccessControlConfigMappingRepository;
import com.yuchen.saas.park.service.mapper.door.config.DoorAccessControlTimeConfigDetailsRepository;
import com.yuchen.saas.park.service.mapper.door.config.DoorAccessControlUserPermissionsRepository;
import com.yuchen.saas.park.service.service.adapter.AdapterComponent;
import com.yuchen.saas.park.service.service.domain.DoorAccessControlUserPermissionsSave;
import com.yuchen.saas.park.service.service.door.config.DoorAccessControlConfigMappingComponent;
import com.yuchen.saas.park.service.service.door.config.DoorAccessControlConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Positive;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static java.util.Optional.ofNullable;

@Transactional
@Service
@Slf4j
@RequiredArgsConstructor
public class DoorAccessControlConfigServiceImpl implements DoorAccessControlConfigService {
    private final DoorAccessControlCardRepository doorAccessControlCardRepository;
    private final DoorAccessControlCardBiometricsRepository doorAccessControlCardBiometricsRepository;

    private final DoorAccessControlConfigMappingRepository doorAccessControlConfigMappingRepository;
    private final DoorAccessControlTimeConfigDetailsRepository doorAccessControlTimeConfigDetailsRepository;

    private final DoorAccessControlUserPermissionsRepository doorAccessControlUserPermissionsRepository;

    private final AdapterComponent adapterComponent;
    private final DoorAccessControlConfigMappingComponent doorAccessControlConfigMappingComponent;

    /**
     * 绑定门禁控制配置
     *
     * @param target 门禁控制配置目标对象
     * @param setting 门禁控制配置设置对象
     */
    @Override
    public void bind(DoorAccessControlConfigCombinedTarget target, DoorAccessControlConfigSetting setting) {
        // 获取门禁控制分组ID集合
        val doorAccessControlGroupIds = ofNullable(target.getDoorAccessControlGroupIds()).orElse(Set.of());
        // 获取门禁控制ID集合
        val doorAccessControlIds = ofNullable(target.getDoorAccessControlIds()).orElse(Set.of());
        // 根据门禁控制分组ID获取对应的门禁分组门禁id控制集合
        val doorAccessControlGroupIdsMap = adapterComponent.listDoorAccessControlIdByGroupIds(doorAccessControlGroupIds);

        // 创建批量门禁控制对象
        val batchDoorAccessControl = BatchDoorAccessControl.of(doorAccessControlGroupIds, doorAccessControlGroupIdsMap, doorAccessControlIds);

        // 则根据部门分组批量绑定门禁控制配置
        ofNullable(target.getDepartmentGroups())
            .filter(o -> !o.isEmpty())
            .ifPresent(o -> doorAccessControlConfigMappingComponent.batchBindByDepartment(o, batchDoorAccessControl, setting));

        // 则根据用户分组批量绑定门禁控制配置
        ofNullable(target.getUserGroupIds())
            .filter(o -> !o.isEmpty())
            .ifPresent(o -> doorAccessControlConfigMappingComponent.batchBindByUserGroup(o, batchDoorAccessControl, setting));

        // 则根据用户ID批量绑定门禁控制配置
        ofNullable(target.getUserIds())
            .filter(o -> !o.isEmpty())
            .ifPresent(o -> doorAccessControlConfigMappingComponent.batchBindByUser(o, batchDoorAccessControl, setting));
    }

    @Override
    public void batchDelete(@NotEmpty Set<@Positive Long> ids) {
        doorAccessControlConfigMappingComponent.deleteByIds(ids);
    }

    @Override
    public void batchUpdateById(DoorAccessControlConfigSettingDTO doorAccessControlConfigSettingDTO) {
        List<DoorAccessControlConfigSettingOne> settingOneList = doorAccessControlConfigSettingDTO.getDoorAccessControlConfigSettingOneList();
        if(Func.isNotEmpty(settingOneList)){
            for (DoorAccessControlConfigSettingOne settingOne : settingOneList) {
                ofNullable(doorAccessControlConfigMappingRepository.selectById(settingOne.getId()))
                        .stream()
                        .map(o -> o.setSettingOne(settingOne))
                        .forEach(doorAccessControlConfigMappingRepository::updateById);

                doorAccessControlTimeConfigDetailsRepository.listByParentId(settingOne.getId())
                        .stream()
                        .map(o -> o.setSettingOne(settingOne))
                        .forEach(doorAccessControlTimeConfigDetailsRepository::updateById);
            }
        }
    }

    @Override
    public void batchUpdate(@NotEmpty Set<@Positive Long> ids, DoorAccessControlConfigSetting setting) {
        ofNullable(doorAccessControlConfigMappingRepository.selectBatchIds(ids))
          .stream()
          .flatMap(Collection::stream)
          .map(o -> o.setSetting(setting))
          .forEach(doorAccessControlConfigMappingRepository::updateById);

        doorAccessControlTimeConfigDetailsRepository.listByParentIds(ids)
          .stream()
          .map(o -> o.setSetting(setting))
          .forEach(doorAccessControlTimeConfigDetailsRepository::updateById);
    }

    @Override
    public void triggerUserGroup(@Positive long userGroupId) {

    }

    @Override
    public void triggerDepartmentGroup(DepartmentGroup departmentGroup) {

    }

    @Override
    public void triggerDoorAccessControlGroup(@Positive long doorAccessControlGroupId) {

    }

    @Override
    public void triggerCard(@Positive long cardId) {

    }

    @Override
    public void triggerUserFacial(@Positive long userId) {

    }

    @Override
    public void setPermissions(DoorAccessControlUserPermissionsSave o) {
        val exists = doorAccessControlUserPermissionsRepository.getByUserId(o.getUserId()).orElse(null);

        if (exists != null) {
            Optional.ofNullable(o.getBlacklisted()).ifPresent(exists::setBlacklisted);
            Optional.ofNullable(o.getFrozen()).ifPresent(exists::setFrozen);
            doorAccessControlUserPermissionsRepository.updateById(exists);
            return;
        }

        val p = new DoorAccessControlUserPermissions().setUserId(o.getUserId());
        Optional.ofNullable(o.getBlacklisted()).ifPresent(p::setBlacklisted);
        Optional.ofNullable(o.getFrozen()).ifPresent(p::setFrozen);
        doorAccessControlUserPermissionsRepository.insert(p);
    }

    @Override
    public void batchSaveBlacklisted(@NotEmpty Set<@Positive Long> userIds) {
        userIds.stream().map(o -> DoorAccessControlUserPermissionsSave.of(o, true, null)).forEach(this::setPermissions);
    }

    @Override
    public void batchDeleteBlacklistedByUserIds(@NotEmpty Set<@Positive Long> userIds) {
        doorAccessControlUserPermissionsRepository.updateBlacklistedByUserIds(userIds, false);
    }

    @Override
    public IPage<DoorAccessControlBlacklistedRO> pageBlacklisted(PageWrapper<DoorAccessControlBlacklistedCondition> o) {
        return doorAccessControlUserPermissionsRepository.page(o.getPage(), o.getT());
    }
}
