package ru.yandex.webmaster3.worker.sitetree;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
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.core.worker.task.TaskResult;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.worker.PeriodicTask;
import ru.yandex.webmaster3.worker.TaskSchedule;

/**
 * Created by ifilippov5 on 14.06.17.
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UploadWebmasterUnverifiedHostsTask extends PeriodicTask<UploadWebmasterUnverifiedHostsTask.TaskState> {
    private static final String[] UNVERIFIED_HOSTS_COLUMN_NAME = {"user_id", "host_id", "host_url", "verification_type",
            "verification_uin", "export_date"};

    private final UserHostsService userHostsService;
    @Value("${webmaster3.worker.uploadWebmasterHostsTask.unverifiedHosts.tmp.file}")
    private final File tmpUnverifiedHostsFile;
    @Value("${webmaster3.worker.uploadWebmasterHostsTask.arnold.export.archive.unverifiedHosts.path}")
    private final YtPath arnoldUnverifiedHostsExportPath;
    @Value("${webmaster3.worker.uploadWebmasterHostsTask.arnold.export.archive.unverifiedHosts.latest.link.path}")
    private final YtPath arnoldUnverifiedHostsLatestLinkPath;
    private final UploadWebmasterHostsCommonService uploadWebmasterHostsCommonService;

    private TaskState state;

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

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

        runUploadUnverifiedHosts(arnoldUnverifiedHostsExportPath, true,
                () -> state.unverifiedHostsSentToArnold++);

        return new PeriodicTask.Result(TaskResult.SUCCESS);
    }

    private boolean runUploadUnverifiedHosts(YtPath exportPath, boolean needDownloadFromCassandra,
                                             UploadWebmasterHostsCommonService.HostSavedListener listener) throws IOException, YtException {
        if (tmpUnverifiedHostsFile.exists()) {
            tmpUnverifiedHostsFile.delete();
        }

        log.info("Check if the data already uploaded today...");
        if (uploadWebmasterHostsCommonService.existTodayTable(exportPath)) {
            log.info("Data has already been uploaded today");
            return true;
        }
        log.info("Upload required");

        if (needDownloadFromCassandra) {
            downloadDataFromCassandra();
        }

        final String tempName = "webmaster-unverified-hosts." + UploadWebmasterHostsCommonService.DATE_FORMAT_IN_NODE_NAME.print(DateTime.now());

        try (BufferedReader br = new BufferedReader(new FileReader(tmpUnverifiedHostsFile))) {
            uploadWebmasterHostsCommonService.executeYtService(exportPath, arnoldUnverifiedHostsLatestLinkPath, tempName, br, UNVERIFIED_HOSTS_COLUMN_NAME,
                    listener);
        } catch (YtException e) {
            throw new YtException("Unable upload unverified hosts to " + exportPath, e);
        } catch (IOException e) {
            throw new IOException("Unable to read from temp file", e);
        }

        return false;
    }

    private void downloadDataFromCassandra() throws IOException {
        log.info("Download unverified hosts from cassandra...");
        String exportDate = LocalDate.now().toString();
        try (PrintWriter pw = new PrintWriter(tmpUnverifiedHostsFile)) {
            userHostsService.forEachMayBeUnverifiedHosts(
                    record -> {
                        pw.println(record.getUserId());
                        pw.println(record.getHostId());
                        pw.println(IdUtils.hostIdToUrl(record.getHostId()));
                        pw.println(record.getVerificationType());
                        pw.println(record.getVerificationUin());
                        pw.println(exportDate);
                        state.unverifiedHostsLoaded++;
                    }
            );
        } catch (IOException e) {
            throw new IOException("Unable to write to temp file", e);
        }
        log.info("Unverified hosts downloaded from cassandra {}", state.unverifiedHostsLoaded);
    }

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

    public static class TaskState implements PeriodicTaskState {
        private long unverifiedHostsLoaded = 0;
        private long unverifiedHostsSentToArnold = 0;

        public long getUnverifiedHostsLoaded() {
            return unverifiedHostsLoaded;
        }

        public long getUnverifiedHostsSentToArnold() {
            return unverifiedHostsSentToArnold;
        }
    }
}
