package ru.yandex.webmaster3.viewer.http.radar;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.autodoc.common.doc.annotation.Description;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.ActionResponse;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.RequestQueryProperty;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.notification.LanguageEnum;
import ru.yandex.webmaster3.storage.radar.RadarThematics;
import ru.yandex.webmaster3.storage.radar.RadarThematicsYDao;
import ru.yandex.webmaster3.storage.user.UserPersonalInfo;
import ru.yandex.webmaster3.storage.user.service.UserPersonalInfoService;
import ru.yandex.webmaster3.viewer.http.AbstractUserAction;
import ru.yandex.webmaster3.viewer.http.AbstractUserRequest;
import ru.yandex.webmaster3.viewer.http.radar.ListRadarThematicsAction.Request;
import ru.yandex.webmaster3.viewer.http.radar.ListRadarThematicsAction.Response;

/**
 * Created by Oleg Bazdyrev on 03/12/2018.
 */
@ReadAction
@Category("searchquery")
@Component("/radar/thematics/list")
@Description("Получение списка категорий Радара")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ListRadarThematicsAction extends AbstractUserAction<Request, Response> {

    private Supplier<Map<LanguageEnum, List<RadarThematicsView>>> radarThematicsSupplier;

    private final RadarThematicsYDao radarThematicsYDao;
    private final UserPersonalInfoService userPersonalInfoService;

    public void init() {
        radarThematicsSupplier = Suppliers.memoizeWithExpiration(this::getAllRadarThematics, 5L, TimeUnit.MINUTES);
    }

    private Map<LanguageEnum, List<RadarThematicsView>> getAllRadarThematics() {
        Map<String, List<RadarThematics>> rawThematicsMap =
                radarThematicsYDao.listAll().stream().filter(RadarThematics::isVisible)
                        .collect(Collectors.groupingBy(RadarThematics::getParentId));
        // раскидываем по локализациям
        Map<LanguageEnum, List<RadarThematicsView>> result = new EnumMap<>(LanguageEnum.class);
        for (LanguageEnum lang : LanguageEnum.values()) {
            List<RadarThematicsView> list = new ArrayList<>();
            result.put(lang, list);
            rawThematicsMap.getOrDefault(RadarThematics.ROOT_ID, Collections.emptyList()).forEach(rt -> {
                RadarThematicsView view = RadarThematicsView.fromRadarThematics(rt, lang);
                list.add(view);
                rawThematicsMap.getOrDefault(rt.getId(), Collections.emptyList()).forEach(childRt -> view.getChildThematics().add(RadarThematicsView.fromRadarThematics(childRt, lang)));
                // sort
                view.getChildThematics().sort(null);
            });
            list.sort(null);
        }
        return result;
    }

    @Override
    public Response process(Request request) throws WebmasterException {
        LanguageEnum language = request.lang;
        if (language == null) {
            UserPersonalInfo personalInfo = userPersonalInfoService.getUserPersonalInfo(request.getUserId());
            language = personalInfo.getLanguage();
        }
        return new Response(radarThematicsSupplier.get().get(language));
    }

    public static final class Request extends AbstractUserRequest {

        private LanguageEnum lang;

        @RequestQueryProperty
        @Description("Язык локали пользователя")
        public void setLang(LanguageEnum lang) {
            this.lang = lang;
        }
    }

    public static final class Response implements ActionResponse.NormalResponse {

        private final List<RadarThematicsView> thematics;

        public Response(List<RadarThematicsView> thematics) {
            this.thematics = thematics;
        }

        @Description("Список категорий (тем) Радара")
        public List<RadarThematicsView> getThematics() {
            return thematics;
        }
    }

    public static final class RadarThematicsView implements Comparable<RadarThematicsView> {

        private final String id;
        private final String name;
        private final List<RadarThematicsView> childThematics;

        public RadarThematicsView(String id, String name, List<RadarThematicsView> childThematics) {
            this.id = id;
            this.name = name;
            this.childThematics = childThematics;
        }

        public static RadarThematicsView fromRadarThematics(RadarThematics rt, LanguageEnum language) {
            String name = rt.getNames().getOrDefault(language, rt.getNames().get(LanguageEnum.RU));
            return new RadarThematicsView(rt.getFullId(), name,
                    rt.getParentId().equals(RadarThematics.ROOT_ID) ? new ArrayList<>() : null);
        }

        @Description("Идентификатор категории")
        public String getId() {
            return id;
        }

        @Description("Локализованное название")
        public String getName() {
            return name;
        }

        @Description("Дочерние тематики")
        public List<RadarThematicsView> getChildThematics() {
            return childThematics;
        }

        @Override
        public int compareTo(@NotNull RadarThematicsView o) {
            return name.compareTo(o.name);
        }
    }

}
