package ru.yandex.webmaster3.storage.http.dao;

import java.util.UUID;

import org.joda.time.DateTime;
import org.springframework.stereotype.Repository;

import ru.yandex.webmaster3.storage.async.model.AsyncOperationRequestInfo;
import ru.yandex.webmaster3.storage.async.model.AsyncTaskType;
import ru.yandex.webmaster3.storage.async.model.HttpAsyncRequestInfoRequestState;
import ru.yandex.webmaster3.storage.async.model.HttpAsyncRequestInfoResultType;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.DataMapper;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Fields;

/**
 * @ishalaru: Class proxy for working with table async_request_info in storage
 * <p>
 * <p>
 * expiration_time для этой таблицы 1 день по полю last_update
 */
@Repository
public class AsyncOperationInfoYDao extends AbstractYDao {

    private static final String TABLE_NAME = "async_request_info";

    protected AsyncOperationInfoYDao() {
        super(PREFIX_WEBMASTER3, TABLE_NAME);
    }

    public void insert(UUID requestId, DateTime date, AsyncTaskType asyncTaskType, int version, String requestData) {
        upsert(F.REQUEST_ID.value(requestId),
                F.LAST_UPDATE.value(date),
                F.ASYNC_TASK_TYPE.value(asyncTaskType),
                F.VERSION.value(version),
                F.JSON_REQUEST_DATA.value(requestData),
                F.STATE.value(HttpAsyncRequestInfoRequestState.NEW)
        ).execute();
    }

    public void updateState(UUID requestId, HttpAsyncRequestInfoRequestState state) {
        update()
                .with(F.STATE.set(state))
                .and(F.LAST_UPDATE.set(DateTime.now()))
                .where(F.REQUEST_ID.eq(requestId))
                .execute();
    }

    public void saveResponse(UUID requestId, int responseObjectTypeId, String responseData) {
        update()
                .with(F.STATE.set(HttpAsyncRequestInfoRequestState.TASK_FINISHED))
                .and(F.RESULT.set(responseData))
                .and(F.RESPONSE_OBJECT_TYPE_ID.set(responseObjectTypeId))
                .and(F.LAST_UPDATE.set(DateTime.now()))
                .and(F.RESULT_TYPE.set(HttpAsyncRequestInfoResultType.OK))
                .where(F.REQUEST_ID.eq(requestId))
                .execute();
    }

    public void saveFailedTaskInfo(UUID requestId, HttpAsyncRequestInfoResultType resultType) {
        update()
                .with(F.STATE.set(HttpAsyncRequestInfoRequestState.TASK_FINISHED))
                .and(F.RESULT_TYPE.set(resultType))
                .and(F.LAST_UPDATE.set(DateTime.now()))
                .where(F.REQUEST_ID.eq(requestId))
                .execute();
    }

    public AsyncOperationRequestInfo getRequest(UUID requestId) {
        return select(MAPPER)
                .where(F.REQUEST_ID.eq(requestId))
                .queryOne();
    }

    private static final DataMapper<AsyncOperationRequestInfo> MAPPER = DataMapper.create(
            F.REQUEST_ID, F.LAST_UPDATE, F.ASYNC_TASK_TYPE, F.VERSION,
            F.JSON_REQUEST_DATA, F.STATE, F.RESULT_TYPE, F.RESPONSE_OBJECT_TYPE_ID, F.RESULT,
            AsyncOperationRequestInfo::new
    );


    private static class F {
        static final Field<UUID> REQUEST_ID = Fields.uuidField("request_id");
        static final Field<DateTime> LAST_UPDATE = Fields.jodaDateTimeField("last_update");
        static final Field<AsyncTaskType> ASYNC_TASK_TYPE = Fields.intEnumField("model_type", AsyncTaskType.R);
        static final Field<Integer> VERSION = Fields.intField("model_version");
        static final Field<String> JSON_REQUEST_DATA = Fields.stringField("json_request_data");
        static final Field<Integer> RESPONSE_OBJECT_TYPE_ID = Fields.intField("response_object_type_ID").withDefault(0);
        static final Field<HttpAsyncRequestInfoRequestState> STATE = Fields.intEnumField("state", HttpAsyncRequestInfoRequestState.R);
        static final Field<HttpAsyncRequestInfoResultType> RESULT_TYPE = Fields.intEnumField("result_type", HttpAsyncRequestInfoResultType.R).makeOptional();
        static final Field<String> RESULT = Fields.stringField("result").makeOptional();
    }
}
