package ru.yandex.webmaster3.worker.feeds;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.base.BaseDateTime;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.core.feeds.feed.FeedServiceType;
import ru.yandex.webmaster3.core.feeds.feed.NativeFeedInfo2;
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.feeds.FeedsNative2YDao;
import ru.yandex.webmaster3.storage.util.yt.TableWriter;
import ru.yandex.webmaster3.storage.util.yt.YtColumn;
import ru.yandex.webmaster3.storage.util.yt.YtCypressService;
import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.YtNode;
import ru.yandex.webmaster3.storage.util.yt.YtNodeAttributes;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtSchema;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.storage.util.yt.YtTableData;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;


/**
 * @author kravchenko99
 * @date 8/20/21
 */


@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Setter
public class ExportNativeUnisearchFeedsTask extends PeriodicTask<ExportNativeUnisearchFeedsTask.TaskState> {

    private final FeedsNative2YDao feedsNativeYDao;
    private final YtService ytService;

    private YtPath hahnYtPath;
    private YtPath arnoldYtPath;
    private boolean moderation;
    private PeriodicTaskType type;
    private String tableName;

    @Override
    public Result run(UUID runId) throws Exception {
        setState(new TaskState(0));
        YtTableData tableData = ytService.prepareTableData(tableName, tableWriter -> {
            feedsNativeYDao.forEach(info -> {
                if (info.getStatusScc().isModeration() == moderation) {
                    write(info, tableWriter);
                    getState().count++;
                }
            });
        });
        try {
            List.of(arnoldYtPath, hahnYtPath)
                    .parallelStream()
                    .forEach(path -> ytService.inTransaction(path).execute(cypressService -> uploadToYt(cypressService, path, tableData)));
        } finally {
            tableData.delete();
        }
        return new Result(TaskResult.SUCCESS);
    }

    private static boolean uploadToYt(YtCypressService cypressService, YtPath path, YtTableData tableData)
            throws YtException {
        // создаем табличку
        YtNodeAttributes attributes = new YtNodeAttributes().setSchema(F.SCHEMA);
        cypressService.remove(path, false, true);
        cypressService.create(path, YtNode.NodeType.TABLE, true, attributes, true);
        // пишем
        cypressService.writeTable(path, tableData);

        return true;
    }

    private static void write(NativeFeedInfo2 info, TableWriter tw) throws YtException {
        for (Integer regionId : info.getRegionsId()) {
            F.DOMAIN.set(tw, info.getDomain());
            F.HOST.set(tw, info.getDomain());
            F.FEED_URL.set(tw, info.getUrl());
            F.LOGIN.set(tw, info.getLogin());
            F.PASSWORD.set(tw, info.getPassword());
            F.STATUS.set(tw, info.getStatus().name());
            F.TYPE.set(tw, info.getType().getTypeOfferBase());
            F.TYPE_WM.set(tw, info.getType().name());
            F.ENABLED_SERVICE_TYPES.set(tw, info.getEnabledServiceTypes());
            F.USER_ID.set(tw, info.getUserId());
            F.REGION_ID.set(tw, (long)regionId);
            F.REGIONS.set(tw, info.getRegionsId());
            F.ADD_DATE.set(tw, info.getAddDate().getMillis());
            F.ENABLED.set(tw, info.isEnabled());
            F.STATUS_SCC.set(tw, info.getStatusScc().getStatus());
            F.STATUS_SCC_WM.set(tw, info.getStatusScc().name());
            F.SCC_TIMESTAMP.set(tw, Optional.ofNullable(info.getSccTimestamp()).map(BaseDateTime::getMillis).orElse(0L));
            tw.rowEnd();

        }
    }

    private interface F {
        YtSchema SCHEMA = new YtSchema();
        YtColumn<String> DOMAIN = SCHEMA.addColumn("domain", YtColumn.Type.STRING);
        YtColumn<String> HOST = SCHEMA.addColumn("host", YtColumn.Type.STRING);
        YtColumn<String> FEED_URL = SCHEMA.addColumn("feed_url", YtColumn.Type.STRING);
        YtColumn<String> LOGIN = SCHEMA.addColumn("login", YtColumn.Type.STRING);
        YtColumn<String> PASSWORD = SCHEMA.addColumn("password", YtColumn.Type.STRING);
        YtColumn<String> STATUS = SCHEMA.addColumn("indexing_status", YtColumn.Type.STRING);
        YtColumn<String> STATUS_SCC = SCHEMA.addColumn("status", YtColumn.Type.STRING);
        YtColumn<String> STATUS_SCC_WM = SCHEMA.addColumn("scc_status_wm", YtColumn.Type.STRING);
        YtColumn<String> TYPE = SCHEMA.addColumn("type", YtColumn.Type.STRING);
        YtColumn<String> TYPE_WM= SCHEMA.addColumn("type_wm", YtColumn.Type.STRING);
        YtColumn<Set<FeedServiceType>> ENABLED_SERVICE_TYPES = SCHEMA.addColumn("enabled_services",
                YtColumn.Type.any());
        YtColumn<Long> USER_ID = SCHEMA.addColumn("user_id", YtColumn.Type.INT_64);
        YtColumn<Long> REGION_ID = SCHEMA.addColumn("region_id", YtColumn.Type.INT_64);
        YtColumn<List<Integer>> REGIONS = SCHEMA.addColumn("regions", YtColumn.Type.any());
        YtColumn<Long> ADD_DATE = SCHEMA.addColumn("add_date", YtColumn.Type.INT_64);
        YtColumn<Boolean> ENABLED = SCHEMA.addColumn("enabled", YtColumn.Type.BOOLEAN);
        YtColumn<Long> SCC_TIMESTAMP = SCHEMA.addColumn("scc_timestamp", YtColumn.Type.INT_64);
    }

    @Getter
    @AllArgsConstructor
    public static class TaskState implements PeriodicTaskState {
        int count;
    }

    @Override
    public PeriodicTaskType getType() {
        return type;
    }

    @Override
    public TaskSchedule getSchedule() {
        //0 */5 * * * *
        return TaskSchedule.startByCron("0 17/30 * * * *");
    }
}
