package ru.yandex.webmaster3.worker.searchbase;

import java.util.Optional;
import java.util.UUID;

import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.webmaster3.core.searchbase.SearchBaseUpdateInfo;
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.util.ydb.exception.WebmasterYdbException;
import ru.yandex.webmaster3.storage.searchbase.dao.SearchBaseUpdatesYDao;
import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.storage.util.yt.YtTableData;
import ru.yandex.webmaster3.storage.util.yt.YtTransactionService;
import ru.yandex.webmaster3.storage.util.yt.YtUtils;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

/**
 * Created by ifilippov5 on 14.09.17.
 */
public class UploadSearchBaseUpdatesTask extends PeriodicTask<UploadSearchBaseUpdatesTask.TaskState> {
    private static final Logger log = LoggerFactory.getLogger(UploadSearchBaseUpdatesTask.class);

    private static final String TABLE_NAME = "searchbases";
    private static final String TABLE_SCHEMA = "[" +
            "{'name': 'switch_date', 'type': 'uint64'}, " +
            "{'name': 'collection_date', 'type': 'uint64'}]";

    private YtPath workDir;
    private YtService ytService;

    private SearchBaseUpdatesYDao searchBaseUpdatesYDao;

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

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

    @Override
    public PeriodicTask.Result run(UUID runId) throws Exception {
        state = new UploadSearchBaseUpdatesTask.TaskState();
        setState(state);

        YtPath tablePath = YtPath.path(workDir, TABLE_NAME);
        YtTableData table = null;
        try {
            table = ytService.prepareTableData(tablePath.getName(), (tw) -> {
                try {
                    for (SearchBaseUpdateInfo updateInfo : searchBaseUpdatesYDao.getUpdatesHistoryList()) {
                        tw.column(YtRow.F_SWITCH_DATE, Optional.ofNullable(updateInfo.getBaseSwitchDate())
                                .map(this::toTimestampInSeconds)
                                .orElse(0L));
                        tw.column(YtRow.F_COLLECTION_DATE, Optional.ofNullable(updateInfo.getBaseCollectionDate())
                                .map(this::toTimestampInSeconds)
                                .orElse(0L));

                        tw.rowEnd();
                    }
                } catch (YtException | WebmasterYdbException e) {
                    throw new RuntimeException(e);
                }
            });

            YtTransactionService.TransactionProcess process = new YtUtils.TransactionWriterBuilder(tablePath, table)
                    .withSchema(TABLE_SCHEMA)
                    .build();

            YtUtils.TransactionExecutor writer = new YtUtils.TransactionExecutor(ytService, workDir);
            writer.execute(process);

        } finally {
            if (table != null) {
                table.delete();
            }
        }
        return new PeriodicTask.Result(TaskResult.SUCCESS);
    }

    private long toTimestampInSeconds(Instant date) {
        return date.getMillis() / 1000L;
    }

    @Required
    public void setWorkDir(YtPath workDir) {
        this.workDir = workDir;
    }

    @Required
    public void setYtService(YtService ytService) {
        this.ytService = ytService;
    }

    @Required
    public void setSearchBaseUpdatesYDao(SearchBaseUpdatesYDao searchBaseUpdatesYDao) {
        this.searchBaseUpdatesYDao = searchBaseUpdatesYDao;
    }


    public static class TaskState implements PeriodicTaskState {
    }

    private static class YtRow {
        static final String F_SWITCH_DATE = "switch_date";
        static final String F_COLLECTION_DATE = "collection_date";
    }
}
