package com.nokia.sms.config;

import com.nokia.sms.message.ServerMessageUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * socket服务端
 */
@Slf4j
@Component
public class SocketRunner implements CommandLineRunner {
    private static final int PORT = 50000;
    @Autowired
    private ThreadPoolExecutor executor;

    @Override
    public void run(String... args) {
        CompletableFuture.runAsync(new ServerTask());
    }

    /**
     * 启动socket服务端
     */
    public void runServer() {
        try (ServerSocket server = new ServerSocket(PORT)) {
            log.info("socket服务端已在端口 {} 启动", PORT);
            while (!server.isClosed()) {
                if (executor.getActiveCount() < executor.getCorePoolSize()) {
                    executor.submit(new AcceptTask(server));
                }
            }
        } catch (Exception e) {
            log.error("socket server error：{}", e.getMessage(), e);
            runServer();
        }
    }

    /**
     * 接收socket连接
     */
    public void accept(ServerSocket server) {
        log.info("socket accept");
        try (Socket socket = server.accept();
             OutputStream outputStream = socket.getOutputStream();
             InputStream inputStream = socket.getInputStream()) {
            while (socket.isConnected()) {
                byte[] buffer = new byte[38];
                // 先读取客户端的输入
                int readCount = inputStream.read(buffer);
                log.info("收到来自 {} 的 {} 字节数据: {}", socket.getRemoteSocketAddress(), readCount, buffer);
                // 识别消息 并建立 应返回的消息
                byte[] message = ServerMessageUtil.parse(buffer);
                // 向客户端输出
                outputStream.write(message);
                outputStream.flush();
            }
        } catch (IOException e) {
            log.error("socket accept error: {}", e.getMessage(), e);
        }
    }

    @AllArgsConstructor
    class AcceptTask implements Runnable {
        private ServerSocket server;

        @Override
        public void run() {
            accept(server);
        }
    }

    class ServerTask implements Runnable {
        @Override
        public void run() {
            runServer();
        }
    }
}
