package cn.reghao.oss.console.app.service;

import cn.reghao.jutil.jdk.converter.ByteConverter;
import cn.reghao.jutil.jdk.converter.ByteType;
import cn.reghao.jutil.jdk.result.Result;
import cn.reghao.oss.api.dto.StoreDiskDto;
import cn.reghao.oss.api.dto.StoreInfo;
import cn.reghao.oss.console.account.service.UserContext;
import cn.reghao.oss.console.app.db.repository.StoreNodeRepository;
import cn.reghao.oss.console.app.db.repository.UploadChannelRepository;
import cn.reghao.oss.console.app.model.dto.UploadChannelDto;
import cn.reghao.oss.console.app.model.po.StoreDisk;
import cn.reghao.oss.console.app.model.po.StoreNode;
import cn.reghao.oss.console.app.model.po.UploadChannel;
import cn.reghao.oss.console.app.model.po.UserNode;
import cn.reghao.oss.console.app.model.vo.StoreDiskVO;
import cn.reghao.oss.console.app.model.vo.StoreNodeVO;
import cn.reghao.oss.console.app.rpc.StoreServiceWrapperImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2024-02-23 15:14:53
 */
@Service
public class StoreChannelService {
    private final ByteConverter byteConverter = new ByteConverter();
    private final UploadChannelRepository uploadChannelRepository;
    private final StoreNodeRepository storeNodeRepository;
    private final UserNodeService userNodeService;
    private final StoreServiceWrapperImpl storeServiceWrapper;

    public StoreChannelService(UploadChannelRepository uploadChannelRepository, StoreNodeRepository storeNodeRepository,
                               UserNodeService userNodeService, StoreServiceWrapperImpl storeServiceWrapper) {
        this.uploadChannelRepository = uploadChannelRepository;
        this.storeNodeRepository = storeNodeRepository;
        this.userNodeService = userNodeService;
        this.storeServiceWrapper = storeServiceWrapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized Result add(UploadChannelDto uploadChannelDto) {
        int createBy = UserContext.getUserId();
        int nodeId = uploadChannelDto.getNodeId();
        UserNode userNode = userNodeService.getUserNode(nodeId, createBy);
        if (userNode == null) {
            return Result.fail(String.format("store_node with id %s not exist", nodeId));
        }

        //int createBy = 410;
        String channelPrefix = uploadChannelDto.getChannelPrefix();
        UploadChannel uploadChannel = uploadChannelRepository.findByPrefixAndCreateByAndNodeId(channelPrefix, createBy, nodeId);
        if (uploadChannel != null) {
            return Result.fail(String.format("channel_prefix %s exist", channelPrefix));
        }

        uploadChannel = uploadChannelRepository.findByPrefixAndNodeId(channelPrefix, nodeId);
        if (uploadChannel != null) {
            return Result.fail(String.format("someone has already created channel_prefix %s", channelPrefix));
        }

        int channelId = getNextChannelId(createBy);
        uploadChannel = new UploadChannel(channelId, uploadChannelDto, createBy);
        uploadChannelRepository.save(uploadChannel);
        storeServiceWrapper.createChannel(channelId, channelPrefix);
        return Result.success();
    }

    private int getNextChannelId(int userId) {
        int channelId = 101;
        int total = uploadChannelRepository.countByCreateBy(userId);
        return channelId + total;
    }

    public StoreNodeVO getStoreDetail(int nodeId) {
        StoreNode storeNode = storeNodeRepository.findById(nodeId);
        if (storeNode == null) {
            return null;
        }



        StoreInfo storeInfo = storeServiceWrapper.getStoreService(storeNode).getStoreInfo();
        List<StoreDiskDto> storeDiskDtos = storeInfo.getStoreDisks();
        List<StoreDisk> list = storeDiskDtos.stream()
                .map(StoreDisk::new)
                .collect(Collectors.toList());
        storeNode.setStoreDisks(list);
        storeNodeRepository.save(storeNode);

        List<StoreDiskVO> storeDisks = storeDiskDtos.stream()
                .map(storeDisk -> {
                    String diskDir = storeDisk.getDiskDir();
                    long total = storeDisk.getTotal();
                    String totalStr = byteConverter.convert(ByteType.Bytes, total);
                    long avail = storeDisk.getAvail();
                    String availStr = byteConverter.convert(ByteType.Bytes, avail);
                    return new StoreDiskVO(diskDir, totalStr, availStr);
                }).collect(Collectors.toList());

        return new StoreNodeVO(storeNode, storeDisks, storeInfo);
    }
}
