package ru.yandex.webmaster3.storage.mirrors.service;

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

import com.datastax.driver.core.utils.UUIDs;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.data.WebmasterUser;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.worker.client.WorkerClient;
import ru.yandex.webmaster3.core.worker.task.ChangeMainMirrorTaskData;
import ru.yandex.webmaster3.storage.mirrors.dao.MainMirrorRequestsYDao;
import ru.yandex.webmaster3.storage.mirrors.data.MirrorActionEnum;
import ru.yandex.webmaster3.storage.mirrors.data.MirrorRequest;
import ru.yandex.webmaster3.storage.mirrors.data.MirrorRequestStateEnum;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;

/**
 * Provides service for CRUD operations on main mirror requests visible to user and mirror request processing queue.
 * <p>
 * User: azakharov
 * Date: 07.07.15
 * Time: 13:36
 */
@Component("mainMirrorService")
public class MainMirrorService {
    public static final Duration EXPIRE_PERIOD = Duration.standardDays(60);

    private final MainMirrorRequestsYDao mainMirrorRequestsYDao;

    private final WorkerClient workerClient;

    @Autowired
    public MainMirrorService(MainMirrorRequestsYDao mainMirrorRequestsYDao,
                             @Qualifier("lbWorkerClient") WorkerClient workerClient) {
        this.mainMirrorRequestsYDao = mainMirrorRequestsYDao;
        this.workerClient = workerClient;
    }

    /**
     * Stores new main mirror request to requests table and to mirror queue table
     */
    public MirrorRequest addMoveRequest(WebmasterHostId hostId, WebmasterHostId oldMainMirrorHostId,
                                        WebmasterHostId newMainMirrorHostId) {
        DateTime now = DateTime.now();
        MirrorRequest request = new MirrorRequest(
                hostId,
                UUIDs.timeBased(),
                MirrorRequestStateEnum.NEW,
                oldMainMirrorHostId,
                newMainMirrorHostId,
                now,
                now,
                0,
                null,
                MirrorActionEnum.MOVE,
                false);
        try {
            mainMirrorRequestsYDao.saveRequest(request);
            return request;
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Can not save main mirror request to Cassandra",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e));
        }
    }

    public MirrorRequest addUnstickRequest(WebmasterHostId hostId, WebmasterHostId currentMainMirror) {
        DateTime now = DateTime.now();
        MirrorRequest request = new MirrorRequest(
                hostId,
                UUIDs.timeBased(),
                MirrorRequestStateEnum.NEW,
                currentMainMirror,
                hostId,
                now,
                now,
                0,
                null,
                MirrorActionEnum.UNSTICK,
                false);
        try {
            mainMirrorRequestsYDao.saveRequest(request);
            return request;
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Can not save main mirror request to Cassandra",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e));
        }
    }

    public void scheduleTask(WebmasterHostId hostId) {
        workerClient.enqueueTask(new ChangeMainMirrorTaskData(hostId));
    }

    public MirrorRequest getLatestRequest(WebmasterHostId hostId) {
        try {
            return mainMirrorRequestsYDao.getLatestRequest(hostId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Unable to read main mirror request",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e), e);
        }
    }

    public MirrorRequest getMirrorRequest(WebmasterHostId hostId, UUID requestId) {
        try {
            return mainMirrorRequestsYDao.getMirrorRequest(hostId, requestId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Unable to read main mirror request",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e), e);
        }
    }

    public List<MirrorRequest> getMirrorRequests(WebmasterHostId hostId, DateTime dateFrom, DateTime dateTo, Integer limit) {
        try {
            return mainMirrorRequestsYDao.listMirrorRequests(hostId, dateFrom, dateTo, null, limit);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Unable to read main mirror requests",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e), e);
        }
    }

    public long getMirrorRequestCount(WebmasterHostId hostId, DateTime dateFrom, DateTime dateTo) {
        try {
            return mainMirrorRequestsYDao.countMirrorRequest(hostId, dateFrom, dateTo);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Unable to get main mirror request count",
                    new WebmasterErrorResponse.YDBErrorResponse(this.getClass(), e), e);
        }
    }
}
