package ru.yandex.webmaster3.worker.mirrors;

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

import org.springframework.beans.factory.annotation.Required;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
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.mirrors.dao.MainMirrorRequestsYDao;
import ru.yandex.webmaster3.storage.mirrors.data.MirrorRequest;
import ru.yandex.webmaster3.storage.util.yt.TableWriter;
import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.YtNode;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

/**
 * https://st.yandex-team.ru/WMC-2675
 *
 * @author avhaliullin
 */
public class UploadMirrorRequestsTask extends PeriodicTask<PeriodicTaskState> {
    private MainMirrorRequestsYDao mainMirrorRequestsYDao;
    private YtService ytService;
    private YtPath tablePath;

    @Override
    public Result run(UUID runId) throws Exception {
        YtPath tmpTableName = YtPath.path(tablePath.getParent(), tablePath.getName() + ".tmp");

        List<MirrorRequest> requests = mainMirrorRequestsYDao.listAllRequests();

        ytService.inTransaction(tablePath).execute(cypressService -> {
            if (cypressService.exists(tmpTableName)) {
                cypressService.remove(tmpTableName);
            }
            cypressService.create(tmpTableName, YtNode.NodeType.TABLE, true);
            cypressService.writeTable(tmpTableName, tableWriter -> {
                for (MirrorRequest request : requests) {
                    try {
                        writeKV(tableWriter, "host_id", request.getHostId());
                        writeKV(tableWriter, "request_id", request.getRequestId());
                        writeKV(tableWriter, "attempt_count", request.getAttemptCount());
                        writeKV(tableWriter, "create_date", request.getCreateDate());
                        writeKV(tableWriter, "desired_main_host_id", request.getNewMainMirrorHostId());
                        writeKV(tableWriter, "old_main_host_id", request.getOldMainMirrorHostId());
                        writeKV(tableWriter, "service_response", request.getServiceResponse());
                        writeKV(tableWriter, "state", request.getState().value());
                        writeKV(tableWriter, "update_date", request.getUpdateDate());
                        // реальный user_id больше не шлем из за GDPR, все равно он по факту Роботом не используется
                        writeKV(tableWriter, "user_id", 0L);
                        writeKV(tableWriter,"action", request.getAction().value());
                        tableWriter.rowEnd();
                    } catch (YtException e) {
                        throw new WebmasterException("Failed to write table",
                                new WebmasterErrorResponse.YTServiceErrorResponse(getClass(), e), e);
                    }
                }
            });
            if (cypressService.exists(tablePath)) {
                cypressService.remove(tablePath);
            }
            cypressService.move(tmpTableName, tablePath, true);
            return true;
        });
        return new Result(TaskResult.SUCCESS);
    }

    private void writeKV(TableWriter writer, String key, Object value) {
        String valueString = value == null ? "" : value.toString();
        writer.column(key, valueString);
    }

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

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

    @Required
    public void setMainMirrorRequestsYDao(MainMirrorRequestsYDao mainMirrorRequestsYDao) {
        this.mainMirrorRequestsYDao = mainMirrorRequestsYDao;
    }

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

    @Required
    public void setTablePath(YtPath tablePath) {
        this.tablePath = tablePath;
    }
}
