package com.atlassian.stash.internal.plugin.web.fragments;

import com.atlassian.plugin.PluginAccessor;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

@Component
public class DefaultClientWebInterfaceManager implements ClientWebInterfaceManager {

    // These have to be LoadingCache because getUnchecked is not available on the Cache<> interface
    private LoadingCache<String, List<ClientWebSectionModuleDescriptor>> sections;
    private LoadingCache<String, List<ClientWebItemModuleDescriptor>> items;
    private LoadingCache<String, List<ClientWebPanelModuleDescriptor>> panels;

    private final PluginAccessor pluginAccessor;

    @Autowired
    public DefaultClientWebInterfaceManager(PluginAccessor pluginAccessor) {
        this.pluginAccessor = pluginAccessor;

        this.sections = CacheBuilder.newBuilder().build(new CacheLoader<String, List<ClientWebSectionModuleDescriptor>>() {
            @Override
            public List<ClientWebSectionModuleDescriptor> load(String location) throws Exception {
                return getFragments(location, ClientWebSectionModuleDescriptor.class);
            }
        });

        this.items = CacheBuilder.newBuilder().build(new CacheLoader<String, List<ClientWebItemModuleDescriptor>>() {
            @Override
            public List<ClientWebItemModuleDescriptor> load(String location) throws Exception {
                return getFragments(location, ClientWebItemModuleDescriptor.class);
            }
        });

        this.panels = CacheBuilder.newBuilder().build(new CacheLoader<String, List<ClientWebPanelModuleDescriptor>>() {
            @Override
            public List<ClientWebPanelModuleDescriptor> load(String location) throws Exception {
                return getFragments(location, ClientWebPanelModuleDescriptor.class);
            }
        });
    }

    @Override
    public List<ClientWebSectionModuleDescriptor> getSections(String location) {
        return sections.getUnchecked(location);
    }

    @Override
    public List<ClientWebItemModuleDescriptor> getItems(String location) {
        return items.getUnchecked(location);
    }

    @Override
    public List<ClientWebPanelModuleDescriptor> getPanels(String location) {
        return panels.getUnchecked(location);
    }

    private <T extends AbstractClientWebFragmentModuleDescriptor> List<T> getFragments(String location, Class<T> clazz) {
        if (location == null) {
            return Collections.emptyList();
        }

        return pluginAccessor.getEnabledModuleDescriptorsByClass(clazz).stream()
                .filter(moduleDescriptor -> location.equalsIgnoreCase(moduleDescriptor.getLocation()))
                .collect(Collectors.toList());
    }

    @Override
    public void refresh() {
        sections.invalidateAll();
        items.invalidateAll();
        panels.invalidateAll();
    }
}
