package ru.yandex.webmaster3.worker.feeds;

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

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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)
@Component
public class ExportNativeFeedsTask extends PeriodicTask<ExportNativeFeedsTask.TaskState> {

    private final FeedsNative2YDao feedsNativeYDao;
    private final YtService ytService;
    @Value("${external.yt.service.hahn.root.default}/export/feeds/native_feeds")
    private YtPath ytPath;

    @Override
    public Result run(UUID runId) throws Exception {
        setState(new TaskState(0));
        YtTableData tableData = ytService.prepareTableData("native_feeds", tableWriter -> {
            feedsNativeYDao.forEach(info -> {
                write(info, tableWriter);
                getState().count++;
            });
        });
        try {
            ytService.inTransaction(ytPath).execute(cypressService -> uploadToYt(cypressService, ytPath, 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.create(path, YtNode.NodeType.TABLE, true, attributes, true);
        cypressService.writeTable(path, tableData, false);
        return true;
    }

    private static void write(NativeFeedInfo2 info, TableWriter tw) throws YtException {
        for (Integer regionId : info.getRegionsId()) {
            F.DOMAIN.set(tw, info.getDomain());
            F.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().name());
            F.ENABLED_SERVICE_TYPES.set(tw, info.getEnabledServiceTypes());
            F.USER_ID.set(tw, info.getUserId());
            F.REGION_ID.set(tw, (long)regionId);
            F.ADD_DATE.set(tw, info.getAddDate().getMillis());
            F.ENABLED.set(tw, info.isEnabled());
            F.STATUS_SCC.set(tw, info.getStatusScc().name());
            F.REGIONS.set(tw, info.getRegionsId());
            tw.rowEnd();
        }
    }

    private interface F {
        YtSchema SCHEMA = new YtSchema();
        YtColumn<String> DOMAIN = SCHEMA.addColumn("domain", YtColumn.Type.STRING);
        YtColumn<String> URL = SCHEMA.addColumn("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("scc_status", YtColumn.Type.STRING);
        YtColumn<String> TYPE = SCHEMA.addColumn("type", 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<Long> ADD_DATE = SCHEMA.addColumn("add_date", YtColumn.Type.INT_64);
        YtColumn<Boolean> ENABLED = SCHEMA.addColumn("enabled", YtColumn.Type.BOOLEAN);
        YtColumn<List<Integer>> REGIONS = SCHEMA.addColumn("regions", YtColumn.Type.any());
    }


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

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

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