package com.sikey.wa04.business.infrastructure.adapter.dao;

import com.sikey.wa04.business.domain.adapter.DeviceBindStateAdapter;
import com.sikey.wa04.business.domain.entity.ChildId;
import com.sikey.wa04.business.domain.entity.Device;
import com.sikey.wa04.business.domain.entity.DeviceConfig;
import com.sikey.wa04.business.domain.entity.DeviceId;
import com.sikey.wa04.business.domain.usecase.ChildIdFactory;
import com.sikey.wa04.business.infrastructure.dto.model.DeviceBindModel;
import com.sikey.wa04.business.infrastructure.dto.model.DeviceConfigModel;
import com.sikey.wa04.business.infrastructure.dto.model.DeviceModel;
import com.sikey.wa04.business.infrastructure.repository.DeviceBindRepository;
import com.sikey.wa04.business.infrastructure.repository.DeviceRepository;
import com.sikey.wa04.common.exception.errors.Errors;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.List;
import java.util.Optional;

@Slf4j
@Component
public class DeviceBindStateAdapterImpl implements DeviceBindStateAdapter {

    @Resource
    private DeviceRepository deviceRepository;

    @Resource
    private DeviceBindRepository deviceBindRepository;

    @Override
    public Boolean isBinding(DeviceId deviceId) {
        List<DeviceBindModel> models = deviceBindRepository.findByDeviceId(deviceId.getId());
        return !models.isEmpty();
    }

    @Override
    public Boolean isBinding(String ticket) {
        Optional<DeviceModel> optional = deviceRepository.findByTicket(ticket);
        DeviceModel deviceModel = optional.orElseThrow();
        List<DeviceBindModel> models = deviceBindRepository.findByDeviceId(deviceModel.getId());
        return !models.isEmpty();
    }

    @Override
    public ChildId getBinder(String ticket) {
        Optional<DeviceModel> optional = deviceRepository.findByTicket(ticket);
        return getChildId(optional);
    }

    @Override
    public ChildId getBinder(DeviceId deviceId) {
        Optional<DeviceModel> optional = deviceRepository.findById(deviceId.getId());
        return getChildId(optional);
    }

    private ChildId getChildId(Optional<DeviceModel> optional) {
        if(optional.isEmpty()){
            return ChildId.builder().id("").build();
        }

        DeviceModel deviceModel = optional.get();

        List<DeviceBindModel> models = deviceBindRepository.findByDeviceId(deviceModel.getId());
        if (models.isEmpty()) {
            return null;
        }
        DeviceBindModel deviceBindModel = models.stream().findFirst().orElseThrow();
        return ChildIdFactory.create(deviceBindModel.getChildId());
    }

    @Override
    public void bind(DeviceId deviceId, ChildId childId) {
        if (isBinding(deviceId)) {
            throw Errors.BEEN_BOUND.getException();
        }

        DeviceBindModel deviceBindModel = new DeviceBindModel();
        deviceBindModel.setDeviceId(deviceId.getId());
        deviceBindModel.setChildId(childId.getId());
        deviceBindModel.setCreatedAt(Instant.now());
        deviceBindModel.setUpdatedAt(Instant.now());
        deviceBindRepository.save(deviceBindModel);
    }

    @Override
    public void unbind(DeviceId deviceId) {
        deviceBindRepository.deleteByDeviceId(deviceId.getId());
    }

}
