package ru.yandex.webmaster3.worker.mobile;

import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskState;
import ru.yandex.webmaster3.core.worker.task.PeriodicTaskType;
import ru.yandex.webmaster3.storage.mobile.dao.HostMobileAuditQueueYDao;
import ru.yandex.webmaster3.storage.mobile.HostMobileAuditService;
import ru.yandex.webmaster3.storage.host.service.HostService;
import ru.yandex.webmaster3.storage.host.service.MirrorService2;
import ru.yandex.webmaster3.storage.util.yt.*;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

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

/**
 * @author leonidrom
 */
@Service
public class HostMobileAuditResendStaleRequestsPeriodicTask extends PeriodicTask<HostMobileAuditResendStaleRequestsPeriodicTask.TaskState> {
    private static final Duration STALE_REQUEST_AGE = Duration.standardHours(24);

    private static final YtSchema YT_TABLE_SCHEMA = new YtSchema();
    private static final YtColumn<String> HOST = YT_TABLE_SCHEMA.addColumn("host", YtColumn.Type.STRING);
    private static final YtColumn<String> ADD_DATE = YT_TABLE_SCHEMA.addColumn("add_date", YtColumn.Type.STRING);
    private static final YtColumn<String> RESEND_DATE = YT_TABLE_SCHEMA.addColumn("resend_date", YtColumn.Type.STRING);

    private final HostMobileAuditService hostMobileAuditService;
    private final HostMobileAuditQueueYDao hostMobileAuditQueueYDao;
    private final HostService hostService;
    private final MirrorService2 mirrorService2;
    private final YtService ytService;
    private final YtPath exportPath;

    @Autowired
    public HostMobileAuditResendStaleRequestsPeriodicTask(
            HostMobileAuditService hostMobileAuditService,
            HostMobileAuditQueueYDao hostMobileAuditQueueYDao,
            HostService hostService,
            MirrorService2 mirrorService2,
            YtService ytService,
            @Value("${external.yt.service.arnold.root.default}/export/host-mobile-audit-queue") YtPath exportPath) {
        this.hostMobileAuditService = hostMobileAuditService;
        this.hostMobileAuditQueueYDao = hostMobileAuditQueueYDao;
        this.hostService = hostService;
        this.mirrorService2 = mirrorService2;
        this.ytService = ytService;
        this.exportPath = exportPath;
    }

    @Override
    public Result run(UUID runId) throws Exception {
        setState(new TaskState());

        DateTime resendBeforeDate = DateTime.now().minus(STALE_REQUEST_AGE);
        List<HostMobileAuditQueueYDao.Record> toResend = new ArrayList<>();

        var tableData = ytService.prepareTableData("host-mobile-audit-queue", tableWriter -> {
            hostMobileAuditService.forEachPendingRequest(r -> {
                var hostId = r.getHostId();
                if (!hostService.isHostAdded(hostId) || !mirrorService2.isMainMirror(hostId)) {
                    // удалим из очереди хосты, перепроверять которых уже нет смысла
                    hostMobileAuditQueueYDao.deleteHost(hostId);
                    getState().totalDeleted++;
                    return;
                }

                var resendDate = r.getResendDate();
                var sendDate = resendDate == null ? r.getAddDate() : resendDate;

                HOST.set(tableWriter, IdUtils.hostIdToUrl(hostId));
                ADD_DATE.set(tableWriter, r.getAddDate().toString());
                RESEND_DATE.set(tableWriter, resendDate == null? null : resendDate.toString());
                tableWriter.rowEnd();

                if (sendDate.isBefore(resendBeforeDate)) {
                    toResend.add(r);
                    getState().totalResent++;
                }
            });
        });

        hostMobileAuditService.resendBatch(toResend);

        ytService.inTransaction(exportPath).execute(cypressService -> {
            if (cypressService.exists(exportPath)) {
                cypressService.remove(exportPath);
            }

            YtNodeAttributes attributes = new YtNodeAttributes().setSchema(YT_TABLE_SCHEMA);
            cypressService.create(exportPath, YtNode.NodeType.TABLE, true, attributes);
            cypressService.writeTable(exportPath, tableData);

            return true;
        });


        return Result.SUCCESS;
    }

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

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

    public static class TaskState implements PeriodicTaskState {
        public int totalResent;
        public int totalDeleted;
    }
}
