package com.morefun.tester;

import java.io.*;
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Simple TCP Server Simulator for testing ISO8583 messages
 * This simulates a payment processor server for testing purposes
 */
public class MockPaymentServer {
    
    private ServerSocket serverSocket;
    private ExecutorService threadPool;
    private boolean running = false;
    
    public static void main(String[] args) {
        MockPaymentServer server = new MockPaymentServer();
        
        // Start server on default port
        int port = args.length > 0 ? Integer.parseInt(args[0]) : 8583;
        
        System.out.println("Starting Mock Payment Server on port " + port);
        System.out.println("Press Ctrl+C to stop server");
        
        // Add shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("\nShutting down server...");
            server.stop();
        }));
        
        server.start(port);
    }
    
    public void start(int port) {
        try {
            serverSocket = new ServerSocket(port);
            threadPool = Executors.newFixedThreadPool(10);
            running = true;
            
            System.out.println("✓ Mock Payment Server started on port " + port);
            System.out.println("✓ Ready to accept ISO8583 connections");
            
            while (running) {
                try {
                    Socket clientSocket = serverSocket.accept();
                    threadPool.submit(new ClientHandler(clientSocket));
                } catch (IOException e) {
                    if (running) {
                        System.err.println("Error accepting connection: " + e.getMessage());
                    }
                }
            }
        } catch (IOException e) {
            System.err.println("Error starting server: " + e.getMessage());
        }
    }
    
    public void stop() {
        running = false;
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
            if (threadPool != null) {
                threadPool.shutdown();
            }
        } catch (IOException e) {
            System.err.println("Error stopping server: " + e.getMessage());
        }
    }
    
    /**
     * Handles individual client connections
     */
    private static class ClientHandler implements Runnable {
        private Socket clientSocket;
        
        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }
        
        @Override
        public void run() {
            String clientAddress = clientSocket.getRemoteSocketAddress().toString();
            System.out.println("✓ New connection from: " + clientAddress);
            
            try (BufferedInputStream in = new BufferedInputStream(clientSocket.getInputStream());
                 BufferedOutputStream out = new BufferedOutputStream(clientSocket.getOutputStream())) {
                
                // Read message length (4 bytes)
                byte[] lengthBuffer = new byte[4];
                int bytesRead = in.read(lengthBuffer);
                
                if (bytesRead < 4) {
                    System.err.println("✗ Invalid message from " + clientAddress + " - no length header");
                    return;
                }
                
                int messageLength = Integer.parseInt(new String(lengthBuffer));
                System.out.println("📨 Receiving message of " + messageLength + " bytes from " + clientAddress);
                
                // Read message content
                byte[] messageBuffer = new byte[messageLength];
                bytesRead = in.read(messageBuffer);
                
                if (bytesRead < messageLength) {
                    System.err.println("✗ Incomplete message from " + clientAddress);
                    return;
                }
                
                String message = new String(messageBuffer);
                System.out.println("📨 Message received: " + message.substring(0, Math.min(50, message.length())) + "...");
                
                // Process message and create response
                String response = processMessage(message);
                
                // Send response with length prefix
                String lengthPrefix = String.format("%04d", response.length());
                String fullResponse = lengthPrefix + response;
                
                out.write(fullResponse.getBytes());
                out.flush();
                
                System.out.println("📤 Response sent to " + clientAddress + " (" + response.length() + " bytes)");
                System.out.println("📤 Response: " + response.substring(0, Math.min(50, response.length())) + "...");
                
            } catch (Exception e) {
                System.err.println("✗ Error handling client " + clientAddress + ": " + e.getMessage());
            } finally {
                try {
                    clientSocket.close();
                    System.out.println("✓ Connection closed: " + clientAddress);
                } catch (IOException e) {
                    System.err.println("Error closing connection: " + e.getMessage());
                }
            }
        }
        
        /**
         * Process incoming ISO8583 message and generate response
         */
        private String processMessage(String message) {
            System.out.println("\n--- Processing ISO8583 Message ---");
            
            try {
                // Simple message parsing (real implementation would be more sophisticated)
                if (message.length() < 4) {
                    return createErrorResponse("Invalid message format");
                }
                
                // Extract MTI
                String mti = message.substring(0, 4);
                System.out.println("MTI: " + mti);
                
                // Create response based on MTI
                String responseMTI;
                String responseCode = "00"; // Approved
                String authCode = String.format("%06d", System.currentTimeMillis() % 1000000);
                
                switch (mti) {
                    case "0200": // Sale request
                        responseMTI = "0210"; // Sale response
                        System.out.println("Processing SALE transaction");
                        break;
                    case "0400": // Reversal request
                        responseMTI = "0410"; // Reversal response
                        System.out.println("Processing REVERSAL transaction");
                        break;
                    default:
                        responseMTI = "0810"; // Network management response
                        responseCode = "05"; // Do not honor
                        System.out.println("Unknown MTI: " + mti);
                }
                
                // Build response message (simplified)
                StringBuilder response = new StringBuilder();
                response.append(responseMTI);
                
                // Echo some fields from request (in real implementation, parse properly)
                if (message.length() > 20) {
                    response.append(message.substring(4, Math.min(20, message.length())));
                }
                
                // Add response-specific fields
                response.append("38").append(String.format("%02d", authCode.length())).append(authCode); // Auth code
                response.append("39").append("02").append(responseCode); // Response code
                
                System.out.println("Response MTI: " + responseMTI);
                System.out.println("Response Code: " + responseCode);
                System.out.println("Auth Code: " + authCode);
                System.out.println("--- Processing Complete ---\n");
                
                return response.toString();
                
            } catch (Exception e) {
                System.err.println("Error processing message: " + e.getMessage());
                return createErrorResponse("Processing error");
            }
        }
        
        private String createErrorResponse(String error) {
            System.out.println("Creating error response: " + error);
            return "0810" + "3902" + "96"; // Network management response with system error
        }
    }
}