package ru.yandex.webmaster3.viewer.http.indexing2.urls;

import java.util.Collections;
import java.util.List;

import lombok.Setter;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.codes.HttpCodeGroup;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.storage.AbstractFilter;
import ru.yandex.webmaster3.storage.TextFilterUtil;
import ru.yandex.webmaster3.storage.indexing2.samples.IndexingSamplesService;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexedUrlSampleConditions;
import ru.yandex.webmaster3.storage.indexing2.samples.dao.IndexedUrlSampleField;
import ru.yandex.webmaster3.storage.util.clickhouse2.condition.Condition;
import ru.yandex.webmaster3.storage.util.clickhouse2.condition.Operator;
import ru.yandex.webmaster3.viewer.http.AbstractUrlFilteringAction;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

/**
 * Created by leonidrom on 17/02/2017.
 */
@ReadAction
@Category("indexing")
public class IndexedUrlSamplesAction extends AbstractUrlFilteringAction<IndexedUrlSamplesRequest, IndexedUrlSamplesResponse> {

    @Setter
    private IndexingSamplesService indexingSamplesService;

    @Override
    public IndexedUrlSamplesResponse process(IndexedUrlSamplesRequest request)
            throws WebmasterException {

        Condition condition = makeCondition(request.getParameterFilters())
                .andThen(getNodeCondition(request.getNodeId(), request.getHostId(), IndexedUrlSampleConditions::buildPathCondition));
        long count = indexingSamplesService.getSamplesCount(request.getHostId(), condition);
        if (count == 0L) {
            return new IndexedUrlSamplesResponse(0, Collections.emptyList());
        }
        return new IndexedUrlSamplesResponse(
                count,
                indexingSamplesService.getSamples(
                        request.getHostId(),
                        condition,
                        request.getOrderBy(),
                        request.getOrderDirection(),
                        request.getPage() * request.getPageSize(),
                        request.getPageSize()));
    }

    public static Condition makeCondition(List<? extends AbstractFilter<IndexedUrlSampleField>> filters) {
        Condition condition = Condition.trueCondition();
        if (filters != null) {
            for (AbstractFilter<IndexedUrlSampleField> filter : filters) {
                Operator dateOp = Operator.fromFilterOperation(filter.getOperation());

                switch (filter.getIndicator()) {
                    case LAST_ACCESS_DATE:
                        if (dateOp == null) {
                            throw filter.invalidFilterException();
                        } else {
                            condition = condition.andThen(IndexedUrlSampleConditions.lastAccessCondition(dateOp, filter.parseDate()));
                        }
                        break;
                    case URL:
                        condition = condition.andThen(TextFilterUtil.getTextCondition(filter, IndexedUrlSampleConditions.getUrlFieldName()));
                        break;
                    case CURRENT_CODE:
                        if (filter.getOperation() == AbstractFilter.Operation.EQUAL) {
                            YandexHttpStatus yandexHttpStatus = parseStatusAsYandexHttpStatus(filter);
                            if (yandexHttpStatus != null) {
                                condition = condition.andThen(IndexedUrlSampleConditions.codeEqual(yandexHttpStatus));
                            } else {
                                condition = condition.andThen(IndexedUrlSampleConditions.codeEqual(parseStatus(filter)));
                            }
                        } else {
                            throw filter.invalidFilterException();
                        }
                        break;
                    default:
                        throw new RuntimeException("Not implemented filter for indicator " + filter.getIndicator());
                }
            }
        }

        return condition;
    }

    private static HttpCodeGroup parseStatus(AbstractFilter<IndexedUrlSampleField> filter) {
        return HttpCodeGroup.valueOf(filter.getValue());
    }

    private static YandexHttpStatus parseStatusAsYandexHttpStatus(AbstractFilter<IndexedUrlSampleField> filter) {
        try {
            return YandexHttpStatus.valueOf(filter.getValue());
        } catch (Throwable t) {
            return null;
        }
    }

}
