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

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.qe.dispenser.domain.request.RequestManager;
import ru.yandex.qe.dispenser.domain.util.ApplicationContextProvider;
import ru.yandex.qe.dispenser.ws.Idempotent;

//001 - used for filters priority
//@WebFilter(filterName = "001_idempotentFilter", urlPatterns = "/*", asyncSupported = true)
public class IdempotentFilter implements Filter {
    private static final Logger LOG = LoggerFactory.getLogger(IdempotentFilter.class);

    private boolean isDisabled;

    @Override
    public void init(final @NotNull FilterConfig config) {
        isDisabled = Boolean.parseBoolean(System.getProperty("idempotent.disabled", "False"));
    }

    @Override
    public void doFilter(final @NotNull ServletRequest req,
                         final @NotNull ServletResponse resp,
                         final @NotNull FilterChain chain) throws IOException, ServletException {
        final RequestManager requestManager = ApplicationContextProvider.getBean(RequestManager.class);
        assert requestManager != null;
        final String reqId = req.getParameter(Idempotent.REQUEST_ID);

        //todo stupid check
        assert requestManager != null;

        if (isDisabled) {
            LOG.debug("IdempotentFilter is disables");
            chain.doFilter(req, resp);
        } else {
            try (final AutoCloseable ignored = requestManager.localLock(reqId, TimeUnit.SECONDS.toNanos(1))) {
                final Optional<String> result = reqId == null ? Optional.empty() : requestManager.lockOrResult(reqId);

                if (result.isPresent()) {
                    LOG.debug("{} was allready handled. Return previous result", reqId);
                    resp.setContentType("application/json");
                    resp.getWriter().print(result.get());
                } else {
                    chain.doFilter(req, resp);
                }
            } catch (RuntimeException | IOException | ServletException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void destroy() {
    }
}
