package ru.yandex.webmaster3.worker.radar;

import java.io.IOException;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.notification.LanguageEnum;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.core.worker.task.TaskResult;
import ru.yandex.webmaster3.storage.radar.RadarThematics;
import ru.yandex.webmaster3.storage.radar.RadarThematicsYDao;
import ru.yandex.webmaster3.storage.util.yt.AsyncTableReader;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.storage.util.yt.YtTableRange;
import ru.yandex.webmaster3.storage.util.yt.YtTableReadDriver;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

/**
 * Created by Oleg Bazdyrev on 30/11/2018.
 */
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ImportRadarThematicsTask extends PeriodicTask<PeriodicTaskState> {

    private static final Logger log = LoggerFactory.getLogger(ImportRadarThematicsTask.class);

    private final RadarThematicsYDao radarThematicsYDao;
    private final YtService ytService;

    @Value("${external.yt.service.hahn}://home/radar_top_sites/production/export/thematics")
    private YtPath thematicsDir;

    @Override
    public Result run(UUID runId) throws Exception {
        // синхронизируем тематики
        // ищем последнюю табличку с тематиками
        ytService.withoutTransaction(cypressService -> {
            Optional<YtPath> tablePath = cypressService.list(thematicsDir).stream().max(Comparator.naturalOrder());
            if (tablePath.isEmpty()) {
                log.warn("Tables with radar thematics not found");
                return true;
            }
            // читаем и собираем
            AsyncTableReader<YtRow> tableReader = new AsyncTableReader<>(
                    cypressService, tablePath.get(), YtTableRange.all(),
                    YtTableReadDriver.createYSONDriver(YtRow.class)).withRetry(3);

            try (AsyncTableReader.TableIterator<YtRow> iterator = tableReader.read()) {
                Set<RadarThematics> radarThematicsSet = new HashSet<>();
                while (iterator.hasNext()) {
                    YtRow row = iterator.next();
                    RadarThematics thematics = row.toRadarThematics();
                    radarThematicsSet.add(thematics);
                    radarThematicsYDao.insert(thematics);
                }
                Set<RadarThematics> existed = new HashSet<>(radarThematicsYDao.listAll());
                // удалим лишние
                existed.removeAll(radarThematicsSet);
                for (RadarThematics toRemove : existed) {
                    radarThematicsYDao.delete(toRemove);
                }
            } catch (IOException e) {
                throw new WebmasterException("Yt error",
                        new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
            }

            return true;
        });
        return new Result(TaskResult.SUCCESS);
    }

    @Override
    public PeriodicTaskType getType() {
        return PeriodicTaskType.IMPORT_RADAR_THEMATICS;
    }

    @Override
    public TaskSchedule getSchedule() {
        return TaskSchedule.startByCron("0 15 7 * * *");
    }

    private static final class YtRow {

        private final List<String> ids;
        private final String name;
        private final NameLocalizations nameLocalizations;
        private final boolean visible;

        @JsonCreator
        public YtRow(@JsonProperty("id") List<String> ids,
                     @JsonProperty("name") String name,
                     @JsonProperty("name_localizations") NameLocalizations nameLocalizations,
                     @JsonProperty("visible") boolean visible) {
            this.ids = ids;
            this.name = name;
            this.nameLocalizations = nameLocalizations;
            this.visible = visible;
        }

        public RadarThematics toRadarThematics() {
            String id = ids.get(ids.size() - 1);
            String parentId = ids.size() > 1 ? ids.get(0) : RadarThematics.ROOT_ID;
            log.info("id = {}, parentId = {}", id, parentId);
            Map<LanguageEnum, String> names = new EnumMap<>(LanguageEnum.class);
            names.put(LanguageEnum.RU, name);
            names.put(LanguageEnum.TR, nameLocalizations.tr);
            names.put(LanguageEnum.EN, nameLocalizations.en);
            return new RadarThematics(parentId, id, names, visible);
        }
    }

    private static final class NameLocalizations {

        private final String en;
        private final String tr;

        @JsonCreator
        public NameLocalizations(
                @JsonProperty("en") String en, @JsonProperty("tr") String tr) {
            this.en = en;
            this.tr = tr;
        }
    }
}
