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.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.util.MultiException;
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 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.host.dao.HostsYDao;
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 12.12.16.
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UploadWebmasterAllHostsTask extends PeriodicTask<UploadWebmasterAllHostsTask.TaskState> {
    private static final String[] ALL_HOSTS_COLUMN_NAME = {"host_id", "host_url", "export_date"};

    private final HostsYDao hostsYDao;
    private final UploadWebmasterHostsCommonService uploadWebmasterHostsCommonService;

    private TaskState state;
    @Setter
    private File tmpAllHostsFile;
    @Value("${webmaster3.worker.uploadWebmasterHostsTask.arnold.export.archive.allHosts.path}")
    private YtPath arnoldAllHostsExportPath;
    @Value("${webmaster3.worker.uploadWebmasterHostsTask.arnold.export.archive.allHosts.latest.link.path}")
    private YtPath arnoldAllHostsLatestLinkPath;

    private boolean isDataDownloaded = false;

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

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

        isDataDownloaded = false;
        runUploadAllHosts(arnoldAllHostsExportPath, () -> state.allHostsSentToArnold++);

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

    private void runUploadAllHosts(YtPath exportPath, UploadWebmasterHostsCommonService.HostSavedListener listener) throws YtException, MultiException, IOException {
        log.info("Check if the data already uploaded today...");
        if (uploadWebmasterHostsCommonService.existTodayTable(exportPath)) {
            log.info("Data has already been uploaded today");
        }

        log.info("Upload required");

        if (!isDataDownloaded) {
            downloadDataFromCassandra();
        }

        final String tempName = "webmaster-all-hosts." + UploadWebmasterHostsCommonService.DATE_FORMAT_IN_NODE_NAME.print(DateTime.now());
        try (BufferedReader br = new BufferedReader(new FileReader(tmpAllHostsFile))) {
            uploadWebmasterHostsCommonService.executeYtService(exportPath, arnoldAllHostsLatestLinkPath, tempName, br, ALL_HOSTS_COLUMN_NAME,
                    listener);
        } catch (YtException e) {
            throw new YtException("Unable upload all hosts to " + exportPath, e);
        } catch (IOException e) {
            throw new IOException("Unable to read from temp file", e);
        }

        log.info("All hosts uploaded into {}", exportPath);
    }

    private void downloadDataFromCassandra() throws IOException {
        if (tmpAllHostsFile.exists()) {
            tmpAllHostsFile.delete();
        }

        String exportDate = LocalDate.now().toString();
        log.info("Download all hosts from cassandra...");
        try (PrintWriter pw = new PrintWriter(tmpAllHostsFile)) {
            hostsYDao.forEachHost(hostId -> {
                pw.println(hostId);
                pw.println(IdUtils.hostIdToUrl(hostId));
                pw.println(exportDate);
                state.allHostsLoaded++;
            });
        } catch (IOException e) {
            throw new IOException("Unable to write to temp file", e);
        }

        isDataDownloaded = true;
        log.info("All hosts downloaded from cassandra {}", state.allHostsLoaded);
    }

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

    public static class TaskState implements PeriodicTaskState {
        private long allHostsLoaded = 0;
        private long allHostsSentToArnold = 0;

        public long getAllHostsLoaded() {
            return allHostsLoaded;
        }

        public long getAllHostsSentToArnold() {
            return allHostsSentToArnold;
        }
    }
}
