package ru.yandex.webmaster3.storage.url.common.dao;

import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.storage.url.common.data.UrlCheckRequestData;
import ru.yandex.webmaster3.storage.url.common.data.UrlCheckRequestSource;
import ru.yandex.webmaster3.storage.util.ydb.AbstractYDao;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;
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;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.UUID;

/**
 * @author leonidrom
 */
@Slf4j
public abstract class CommonUrlCheckRequestsYDao extends AbstractYDao {
    public CommonUrlCheckRequestsYDao(String tableSpace, String tableName) {
        super(tableSpace, tableName);
    }

    public List<UrlCheckRequestData> getRequests(WebmasterHostId hostId) {
        var st = select(MAPPER).where(F.HOST_ID.eq(hostId));
        st.order(F.REQUEST_ID.asc());

        return queryForList(st.getStatement(), MAPPER, list -> {
            var maxReq = list.get(list.size() - 1);
            return st.cont(F.REQUEST_ID.gt(maxReq.getRequestId())).getStatement();
        });
    }

    public UrlCheckRequestData getRequest(WebmasterHostId hostId, UUID requestId) {
        return select(MAPPER)
                .where(F.HOST_ID.eq(hostId))
                .and(F.REQUEST_ID.eq(requestId))
                .queryOne();
    }

    public UrlCheckRequestData storeRequest(WebmasterHostId hostId, UUID requestId, URL url,
                                            DateTime createdTime, UrlCheckRequestSource requestSource) {
        UrlCheckRequestData request = new UrlCheckRequestData(hostId, requestId, url, createdTime, requestSource);
        storeRequest(request);

        return request;
    }

    public void storeRequest(UrlCheckRequestData req) {
        insert(
                F.HOST_ID.value(req.getHostId()),
                F.REQUEST_ID.value(req.getRequestId()),
                F.URL.value(req.getUrl().toExternalForm()),
                F.CREATED_TIME.value(req.getCreatedTime()),
                F.REQUEST_SOURCE.value(req.getRequestSource())
        ).execute();
    }

    public void deleteRequest(WebmasterHostId hostId, UUID requestId) {
        delete()
                .where(F.HOST_ID.eq(hostId))
                .and(F.REQUEST_ID.eq(requestId))
                .execute();
    }

    protected static final class F {
        public static final Field<WebmasterHostId> HOST_ID = Fields.hostIdField("host_id");
        public static final Field<UUID> REQUEST_ID = Fields.uuidField("request_id");
        public static final Field<String> URL = Fields.stringField("url");
        public static final Field<DateTime> CREATED_TIME = Fields.jodaDateTimeField("created_time");
        public static final Field<UrlCheckRequestSource> REQUEST_SOURCE = Fields.stringEnumField("request_source", UrlCheckRequestSource.R)
                .withDefault(UrlCheckRequestSource.URL_CHECK);
    }
    
    protected static final DataMapper<UrlCheckRequestData> MAPPER = DataMapper.create(
            F.HOST_ID, F.REQUEST_ID, F.URL, F.CREATED_TIME, F.REQUEST_SOURCE,
            (hostId, requestId, urlS, createdTime, requestSource) -> {
                URL url;
                try {
                    url = new java.net.URL(urlS);
                } catch (MalformedURLException e) {
                    throw new WebmasterYdbException("Failed to read url from DB", e);
                }
                
                return new UrlCheckRequestData(hostId, requestId, url, createdTime, requestSource);
            }
    );
}
