package ru.yandex.webmaster3.worker.feeds;

import java.net.IDN;
import java.util.List;
import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
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.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;

import static ru.yandex.webmaster3.core.worker.task.PeriodicTaskType.FEEDS_EXPORT_TV_FEEDS;


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

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

    private final FeedsNative2YDao feedsNativeYDao;
    private final YtService ytService;

    @Value("${external.yt.service.hahn.root.default}/export/feeds/vertical_share/feeds_info")
    private YtPath hahnYtPath;
    @Value("${external.yt.service.arnold.root.default}/export/feeds/vertical_share/feeds_info")
    private YtPath arnoldYtPath;

    @Override
    public Result run(UUID runId) throws Exception {
        setState(new TaskState(0));
        YtTableData tableData = ytService.prepareTableData("tv_feeds_info", tableWriter -> {
            feedsNativeYDao.forEach(info -> {
                if (info.getBusinessId() != null) {
                    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.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 {
        F.PUNNY_DOMAIN.set(tw, IDN.toUnicode(info.getDomain()));
        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.USER_ID.set(tw, info.getUserId());
        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().name());
        F.FEED_ID.set(tw, info.getFeedId());
        F.BUSINESS_ID.set(tw, info.getBusinessId());
        F.PARTNER_ID.set(tw, info.getPartnerId());
        tw.rowEnd();
    }

    private interface F {
        YtSchema SCHEMA = new YtSchema();
        YtColumn<String> PUNNY_DOMAIN = SCHEMA.addColumn("punny_domain", YtColumn.Type.STRING);
        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("scc_status", YtColumn.Type.STRING);
        YtColumn<Long> USER_ID = SCHEMA.addColumn("user_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<Long> BUSINESS_ID = SCHEMA.addColumn("business_id", YtColumn.Type.INT_64);
        YtColumn<Long> FEED_ID = SCHEMA.addColumn("feed_id", YtColumn.Type.INT_64);
        YtColumn<Long> PARTNER_ID = SCHEMA.addColumn("partner_id", YtColumn.Type.INT_64);
        YtColumn<Boolean> ENABLED = SCHEMA.addColumn("enabled", YtColumn.Type.BOOLEAN);
    }

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

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

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