package easydo.technology.components;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.sql.DataSource;

import easydo.technology.core.ZeroSpringFolder;
import zmo.technology.lite.core.ZeroFolders;
import zmo.technology.lite.core.ZeroFolders.ZeroFolderContainer;
import zmo.technology.lite.core.ZeroFolders.ZeroFolderEntity;
import zmo.technology.lite.core.ZeroRequestGuider;
import zmo.technology.lite.processors.ZeroFolderProcessor;

public class ZeroSpringFolderComponent {

    private DataSource dataSource;

    private ZeroSpringFolderComponent(DataSource dataSource) {
        super();
        this.dataSource = dataSource;
    }

    public static ZeroSpringFolderComponent build(DataSource dataSource) {
        return new ZeroSpringFolderComponent(dataSource);
    }

    @FunctionalInterface
    public interface SafetyProcessor {

        void exec(ZeroFolderProcessor folderProcessor) throws Exception;
    }

    public void safetyFolderProcessor(SafetyProcessor safety) throws SQLException {
        Connection connection = dataSource.getConnection();
        try {
            connection.setAutoCommit(false);
            ZeroRequestGuider guider = ZeroRequestGuider.build();
            guider.setConnection(connection);
            safety.exec(ZeroFolderProcessor.build(guider));
            connection.commit();
        } catch (Exception e) {
            connection.rollback();
            e.printStackTrace();
        } finally {
            connection.close();
        }

    }

    private void reference(String refEntityID, String refDataID, String refDirectory) throws SQLException {
        safetyFolderProcessor(folderProcessor -> {
            ZeroFolderEntity entity = folderProcessor.fetchFolderInfo(refEntityID);
            entity.setRelevancyID(refDataID);
            entity.setDirectory(refDirectory);
            String[] dirs = refDirectory.split("/");
            List<String> paths = new ArrayList<>();
            for (String dir : dirs)
                if (!dir.trim().isEmpty())
                    paths.add(dir);
            paths.add(refEntityID);
            entity.setPath(String.join("/", paths));
            folderProcessor.addRelevancyFolder(entity);
        });
    }

    public void save(ZeroSpringFolder<?> folder) throws Exception {
        if (folder.getFolders() == null)
            return;
        safetyFolderProcessor(folderProcessor -> {
            for (Map.Entry<String, ZeroFolderContainer> entry : folder.getFolders().entrySet()) {
                for (ZeroFolderEntity entity : entry.getValue().getEntities()) {
                    if (entity.getFeatures().containsKey(ZeroFolders.ZERO_FOLDER_ENTITY_TICKET)) {
                        long refCount = folderProcessor.fetchDataRefCount(folder.dataID(), entry.getKey());
                        long i = refCount - entry.getValue().getMaxLimit() + 1;
                        for (; i > 0; i--)
                            folderProcessor.rmLastDataRef(folder.dataID(), entry.getKey());
                        reference(entity.getFeatures().getString(ZeroFolders.ZERO_FOLDER_ENTITY_TICKET),
                                folder.dataID(), entry.getKey());
                    }
                }
            }
        });
    }

    public void clean(ZeroSpringFolder<?> folder) throws Exception {
        safetyFolderProcessor(folderProcessor -> {
            List<ZeroFolderEntity> entities = folderProcessor.fetchDataRef(folder.dataID());
            for (ZeroFolderEntity entity : entities)
                folderProcessor.rmFolder(entity);
        });
    }

    public void fetch(ZeroSpringFolder<?> folder) throws Exception {
        safetyFolderProcessor(folderProcessor -> {
            List<ZeroFolderEntity> entities = folderProcessor.fetchDataRef(folder.dataID());
            for (ZeroFolderEntity entity : entities)
                folder.getFolders().get(entity.getDirectory()).addEntity(entity);
        });
    }
}
