package ru.yandex.webmaster3.worker.task;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import ru.yandex.webmaster3.core.logbroker.reader.IDataProcessing;
import ru.yandex.webmaster3.core.logbroker.reader.MessageContainer;
import ru.yandex.webmaster3.core.solomon.metric.SolomonMetricRegistry;
import ru.yandex.webmaster3.core.worker.client.LogbrokerMultiTopicClient;
import ru.yandex.webmaster3.core.worker.task.WorkerTaskPriority;
import ru.yandex.webmaster3.storage.task.TaskBatchLogYDao;
import ru.yandex.webmaster3.storage.task.TaskStateLogYDao;
import ru.yandex.webmaster3.worker.TaskRegistry;
import ru.yandex.webmaster3.worker.queue.TaskQueueMetrics;
import ru.yandex.webmaster3.worker.queue.TaskScheduler;

/**
 * @author: ishalaru
 * DATE: 06.08.2019
 */
@Slf4j
@RequiredArgsConstructor
public class TaskProcessingService implements IDataProcessing {
    private static final int TERMINATION_TIMEOUT = 10;

    private final TaskRegistry taskRegistry;
    private final SolomonMetricRegistry solomonMetricRegistry;
    private final TaskQueueMetrics taskQueueMetrics;
    private final WorkerTaskPriority workerTaskPriority;
    private final int threadPoolSize;
    private final int queueCapacity;
    private final TaskBatchLogYDao taskBatchLogYDao;
    private final TaskStateLogYDao taskStateLogYDao;
    private final LogbrokerMultiTopicClient logbrokerMultiTopicClient;
    private final TaskScheduler taskScheduler;

    private ExecutorService executorService;
    private BlockingQueue<MessageContainer> queue;

    @PostConstruct
    public void init() {
        executorService = Executors.newFixedThreadPool(
                threadPoolSize,
                new ThreadFactoryBuilder()
                        .setDaemon(true)
                        .setNameFormat(workerTaskPriority.getName() + "-lbtask-worker-%d")
                        .build()
        );
        queue = new ArrayBlockingQueue<>(queueCapacity);
        log.info("Start workers...");
        for (int i = 0; i < threadPoolSize; i++) {
            executorService.execute(new InfinityWorkerRunner(queue, taskQueueMetrics, taskRegistry, logbrokerMultiTopicClient,
                    taskBatchLogYDao, taskStateLogYDao, taskScheduler));
        }
        log.info("Workers started");
    }

    @PreDestroy
    public void destroy() {
        executorService.shutdown();
        try {
            executorService.awaitTermination(TERMINATION_TIMEOUT, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void process(MessageContainer messageContainer) {
        try {
            queue.put(messageContainer);
        } catch (InterruptedException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }


}
