package ru.yandex.qe.dispenser.ws.staff;

import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.Optional;

public final class StaffPersonsQuery {

    private final String query;

    private StaffPersonsQuery(final String query) {
        this.query = query;
    }

    public Optional<String> getQuery() {
        return Optional.ofNullable(query);
    }

    public static Builder builder() {
        return new Builder();
    }

    public static IdFilter idEquals(final long value) {
        return new IdEqualsFilter(value);
    }

    public static IdFilter idGreaterThan(final long value) {
        return new IdGreaterThanFilter(value);
    }

    public static ModifiedAtFilter modifiedAtLessThan(final Instant value) {
        return new ModifiedAtLessThanFilter(value);
    }

    public static ModifiedAtFilter modifiedAtBetween(final Instant greaterOrEqualsThan, final Instant lessThan) {
        return new ModifiedAtBetween(greaterOrEqualsThan, lessThan);
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final StaffPersonsQuery that = (StaffPersonsQuery) o;
        return Objects.equals(query, that.query);
    }

    @Override
    public int hashCode() {
        return Objects.hash(query);
    }

    @Override
    public String toString() {
        return "StaffPersonsQuery{" +
                "query='" + query + '\'' +
                '}';
    }

    public static final class Builder {

        private boolean deleted;
        private IdFilter idFilter;
        private ModifiedAtFilter modifiedAtFilter;
        private String login;
        private String uid;

        private Builder() {
        }

        public Builder deleted(final boolean deleted) {
            this.deleted = deleted;
            return this;
        }

        public Builder idFilter(final IdFilter idFilter) {
            this.idFilter = idFilter;
            return this;
        }

        public Builder modifiedAtFilter(final ModifiedAtFilter modifiedAtFilter) {
            this.modifiedAtFilter = modifiedAtFilter;
            return this;
        }

        public Builder login(final String login) {
            this.login = login;
            return this;
        }

        public Builder uid(final String uid) {
            this.uid = uid;
            return this;
        }

        public StaffPersonsQuery build() {
            if (!deleted && idFilter == null && modifiedAtFilter == null && login == null && uid == null) {
                return new StaffPersonsQuery(null);
            }
            final StringBuilder queryBuilder = new StringBuilder();
            if (deleted) {
                queryBuilder.append("is_deleted == True");
            }
            if (idFilter != null) {
                if (queryBuilder.length() > 0) {
                    queryBuilder.append(" and ");
                }
                queryBuilder.append(idFilter.toQuery());
            }
            if (modifiedAtFilter != null) {
                if (queryBuilder.length() > 0) {
                    queryBuilder.append(" and ");
                }
                queryBuilder.append(modifiedAtFilter.toQuery());
            }
            if (login != null) {
                if (queryBuilder.length() > 0) {
                    queryBuilder.append(" and ");
                }
                queryBuilder.append("login == '");
                queryBuilder.append(login);
                queryBuilder.append("'");
            }
            if (uid != null) {
                if (queryBuilder.length() > 0) {
                    queryBuilder.append(" and ");
                }
                queryBuilder.append("uid == '");
                queryBuilder.append(uid);
                queryBuilder.append("'");
            }
            return new StaffPersonsQuery(queryBuilder.toString());
        }
    }

    public interface IdFilter {

        String toQuery();

    }

    private static final class IdEqualsFilter implements IdFilter {

        private final long value;

        private IdEqualsFilter(final long value) {
            this.value = value;
        }

        @Override
        public String toQuery() {
            return "id == " + value;
        }

    }

    private static final class IdGreaterThanFilter implements IdFilter {

        private final long value;

        private IdGreaterThanFilter(final long value) {
            this.value = value;
        }

        @Override
        public String toQuery() {
            return "id > " + value;
        }

    }

    public interface ModifiedAtFilter {

        String toQuery();

    }

    private static final class ModifiedAtLessThanFilter implements ModifiedAtFilter {

        private final Instant value;

        private ModifiedAtLessThanFilter(final Instant value) {
            this.value = value;
        }

        @Override
        public String toQuery() {
            return "_meta.modified_at < '" + DateTimeFormatter.ISO_INSTANT.format(value) + "'";
        }

    }

    private static final class ModifiedAtBetween implements ModifiedAtFilter {

        private final Instant greaterOrEqualsThan;
        private final Instant lessThan;

        private ModifiedAtBetween(final Instant greaterOrEqualsThan, final Instant lessThan) {
            this.greaterOrEqualsThan = greaterOrEqualsThan;
            this.lessThan = lessThan;
        }

        @Override
        public String toQuery() {
            return "_meta.modified_at >= '" + DateTimeFormatter.ISO_INSTANT.format(greaterOrEqualsThan)
                    + "' and _meta.modified_at < '" + DateTimeFormatter.ISO_INSTANT.format(lessThan) + "'";
        }

    }

}
