package com.alterdekim.hearthhack.component;


import com.alterdekim.hearthhack.component.processor.Processor;
import com.alterdekim.hearthhack.util.Util;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

@Slf4j
@Component
public class TcpServer {

    private final int socketPort = 1119;

    private SSLServerSocket serverSocket;
    private List<TcpConnection> connections;

    private Set<Class<? extends Processor>> processorClasses;

    @Scheduled(fixedDelay = 5000)
    private void start() {
        try {
            processorClasses = new Reflections(this.getClass().getPackageName()).getSubTypesOf(Processor.class);
            if( serverSocket != null && !serverSocket.isClosed() ) {
                serverSocket.close();
                serverSocket = null;
            }
            this.connections = new LinkedList<>();
            this.serverSocket = (SSLServerSocket) Util.getSocketFactory(
                    "test.com.crt", // "test.com.crt"
                    "test.com.crt", // "test.com.crt"
                    "test.com.key", // "test.com.key"
                    ""
            ).createServerSocket(this.socketPort, 15);

            while(true) {
                SSLSocket s = (SSLSocket) serverSocket.accept();
                TcpConnection c = new TcpConnection(s, processorClasses);
                connections.add(c);
                log.info("New Connection Established From {}", s.getInetAddress().toString());
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    public void stopListening() {
        connections.forEach(TcpConnection::stopListeningAndDisconnect);
        try {
            serverSocket.close();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    public void removeConnection(TcpConnection c) {
        connections.remove(c);
    }
}
