package com.morefun.tester;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * Simple ISO8583 Message Builder (without Android dependencies)
 * Demonstrates basic ISO8583 message structure
 */
public class SimpleISO8583MessageTester {
    
    // Transaction data
    private static final String MERCHANT_ID = "900890089008900";
    private static final String TERMINAL_ID = "12345678";
    private static final String TEST_CARD = "4111111111111111";
    
    public void testSaleMessage() throws Exception {
        System.out.println("Creating Simple ISO8583 Sale message...");
        
        // Create message fields
        Map<Integer, String> fields = new HashMap<>();
        
        // Build Sale message
        buildSaleMessage(fields);
        
        // Display message
        displayMessage(fields, "SALE");
        
        // Send via TCP if enabled
        if (NetworkConfig.ENABLE_NETWORK) {
            sendMessage(fields, "SALE");
        } else {
            System.out.println("[SUCCESS] Simple Sale message created successfully (network disabled)");
        }
    }
    
    public void testReversalMessage() throws Exception {
        System.out.println("\nCreating Simple ISO8583 Reversal message...");
        
        // Create message fields
        Map<Integer, String> fields = new HashMap<>();
        
        // Build Reversal message
        buildReversalMessage(fields);
        
        // Display message
        displayMessage(fields, "REVERSAL");
        
        // Send via TCP if enabled
        if (NetworkConfig.ENABLE_NETWORK) {
            sendMessage(fields, "REVERSAL");
        } else {
            System.out.println("[SUCCESS] Simple Reversal message created successfully (network disabled)");
        }
    }
    
    private void buildSaleMessage(Map<Integer, String> fields) {
        // Generate timestamps
        SimpleDateFormat dateFormat = new SimpleDateFormat("MMdd", Locale.US);
        SimpleDateFormat timeFormat = new SimpleDateFormat("HHmmss", Locale.US);
        Date now = new Date();
        
        // Generate trace number
        String traceNo = String.format("%06d", System.currentTimeMillis() % 1000000);
        
        // Build ISO8583 fields
        fields.put(0, "0200");                    // MTI - Financial transaction request
        fields.put(2, TEST_CARD);                 // PAN
        fields.put(3, "000000");                  // Processing code (Sale)
        fields.put(4, "000000001500");           // Amount ($15.00)
        fields.put(11, traceNo);                 // STAN
        fields.put(12, timeFormat.format(now));  // Transaction time
        fields.put(13, dateFormat.format(now));  // Transaction date
        fields.put(14, "2512");                  // Expiry date
        fields.put(22, "012");                   // POS entry mode
        fields.put(25, "00");                    // POS condition code
        fields.put(41, TERMINAL_ID);             // Terminal ID
        fields.put(42, MERCHANT_ID);             // Merchant ID
        fields.put(49, "840");                   // Currency (USD)
        fields.put(62, "000001");                // Batch number
    }
    
    private void buildReversalMessage(Map<Integer, String> fields) {
        // Generate timestamps
        SimpleDateFormat dateFormat = new SimpleDateFormat("MMdd", Locale.US);
        SimpleDateFormat timeFormat = new SimpleDateFormat("HHmmss", Locale.US);
        Date now = new Date();
        
        // Generate trace number (new for reversal)
        String traceNo = String.format("%06d", System.currentTimeMillis() % 1000000);
        
        // Build ISO8583 fields for reversal
        fields.put(0, "0400");                    // MTI - Reversal transaction request
        fields.put(2, TEST_CARD);                 // PAN (same as original)
        fields.put(3, "000000");                  // Processing code (same as original)
        fields.put(4, "000000001500");           // Amount (same as original)
        fields.put(11, traceNo);                 // STAN (new for reversal)
        fields.put(12, timeFormat.format(now));  // Transaction time
        fields.put(13, dateFormat.format(now));  // Transaction date
        fields.put(22, "012");                   // POS entry mode
        fields.put(25, "00");                    // POS condition code
        fields.put(41, TERMINAL_ID);             // Terminal ID
        fields.put(42, MERCHANT_ID);             // Merchant ID
        fields.put(49, "840");                   // Currency (USD)
        fields.put(62, "000001");                // Batch number
    }
    
    private void displayMessage(Map<Integer, String> fields, String messageType) {
        System.out.println("\n--- " + messageType + " Message Details ---");
        System.out.println("MTI: " + fields.get(0));
        System.out.println("PAN: " + maskPAN(fields.get(2)));
        System.out.println("Amount: $" + formatAmount(fields.get(4)));
        System.out.println("STAN: " + fields.get(11));
        System.out.println("Time: " + fields.get(12));
        System.out.println("Date: " + fields.get(13));
        System.out.println("Terminal: " + fields.get(41));
        System.out.println("Merchant: " + fields.get(42));
        
        // Show all fields
        System.out.println("\nAll Fields:");
        fields.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> {
                String value = entry.getValue();
                if (entry.getKey() == 2) value = maskPAN(value); // Mask PAN
                System.out.println(String.format("  Field %03d: %s", entry.getKey(), value));
            });
        
        // Simulate message packing
        StringBuilder packedMessage = new StringBuilder();
        fields.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> packedMessage.append(entry.getValue()));
        
        System.out.println("\n[SUCCESS] Message structure created (" + packedMessage.length() + " chars)");
        System.out.println("Sample packed data: " + 
            packedMessage.substring(0, Math.min(50, packedMessage.length())) + "...");
    }
    
    private String maskPAN(String pan) {
        if (pan == null || pan.length() < 8) return pan;
        return pan.substring(0, 4) + "****" + pan.substring(pan.length() - 4);
    }
    
    private String formatAmount(String amount) {
        if (amount == null) return "0.00";
        try {
            long cents = Long.parseLong(amount);
            return String.format("%.2f", cents / 100.0);
        } catch (Exception e) {
            return amount;
        }
    }
    
    /**
     * Send message via TCP/IP
     */
    private void sendMessage(Map<Integer, String> fields, String messageType) {
        System.out.println("\n=== Sending " + messageType + " via Simple TCP ===");
        System.out.println("Connection: " + NetworkConfig.getConnectionInfo());
        
        try {
            // Test connection first
            boolean connected = SimpleTCPClient.testConnection(
                NetworkConfig.SERVER_IP, 
                NetworkConfig.SERVER_PORT, 
                NetworkConfig.CONNECTION_TIMEOUT
            );
            
            if (!connected && NetworkConfig.ENABLE_BACKUP) {
                System.out.println("Trying backup server...");
                connected = SimpleTCPClient.testConnection(
                    NetworkConfig.BACKUP_IP, 
                    NetworkConfig.BACKUP_PORT, 
                    NetworkConfig.CONNECTION_TIMEOUT
                );
            }
            
            if (!connected) {
                System.out.println("✗ No server available - simulating response");
                simulateResponse(fields, messageType);
                return;
            }
            
            // Pack message for transmission
            String packedMessage = packMessage(fields);
            
            if (NetworkConfig.SHOW_RAW_MESSAGES) {
                System.out.println("Raw Message Hex: " + SimpleTCPClient.toHex(packedMessage));
            }
            
            // Send message
            String response = SimpleTCPClient.sendMessage(
                packedMessage,
                NetworkConfig.SERVER_IP,
                NetworkConfig.SERVER_PORT,
                NetworkConfig.USE_SSL,
                NetworkConfig.READ_TIMEOUT
            );
            
            // Process response
            processResponse(response, messageType);
            
        } catch (Exception e) {
            System.err.println("Error sending " + messageType + ": " + e.getMessage());
            
            if (NetworkConfig.SIMULATE_RESPONSES) {
                System.out.println("Falling back to simulated response...");
                simulateResponse(fields, messageType);
            }
        }
    }
    
    /**
     * Pack message fields into transmittable format
     */
    private String packMessage(Map<Integer, String> fields) {
        StringBuilder packed = new StringBuilder();
        
        // Add TPDU header if enabled
        if (NetworkConfig.USE_TPDU) {
            packed.append(NetworkConfig.TPDU_HEADER);
        }
        
        // Simple packing - just concatenate fields in order
        fields.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> packed.append(entry.getValue()));
            
        return packed.toString();
    }
    
    /**
     * Process server response
     */
    private void processResponse(String response, String messageType) {
        System.out.println("\n=== " + messageType + " Response ===");
        System.out.println("Response Length: " + response.length());
        System.out.println("Response Sample: " + response.substring(0, Math.min(50, response.length())) + "...");
        
        if (NetworkConfig.SHOW_RAW_MESSAGES) {
            System.out.println("Raw Response Hex: " + SimpleTCPClient.toHex(response));
        }
        
        // Parse response (simplified)
        if (response.length() >= 50) {
            // Assume response code is at specific position (this would be proper parsing in real implementation)
            String responseCode = response.length() > 39 ? "00" : "05"; // Simulate response
            
            System.out.println("Response Code: " + responseCode);
            
            if ("00".equals(responseCode)) {
                System.out.println("[SUCCESS] TRANSACTION APPROVED");
            } else {
                System.out.println("[DECLINED] TRANSACTION DECLINED - Code: " + responseCode);
            }
        } else {
            System.out.println("[ERROR] Invalid response format");
        }
    }
    
    /**
     * Simulate response for testing when network is disabled
     */
    private void simulateResponse(Map<Integer, String> fields, String messageType) {
        System.out.println("\n=== Simulated " + messageType + " Response ===");
        
        // Create simulated response
        Map<Integer, String> responseFields = new HashMap<>();
        responseFields.put(0, fields.get(0).equals("0200") ? "0210" : "0410"); // Response MTI
        responseFields.put(2, fields.get(2));  // Echo PAN
        responseFields.put(4, fields.get(4));  // Echo amount
        responseFields.put(11, fields.get(11)); // Echo STAN
        responseFields.put(38, "123456");      // Auth code
        responseFields.put(39, "00");          // Response code (approved)
        responseFields.put(41, fields.get(41)); // Echo terminal ID
        responseFields.put(42, fields.get(42)); // Echo merchant ID
        
        System.out.println("MTI: " + responseFields.get(0));
        System.out.println("Response Code: " + responseFields.get(39));
        System.out.println("Auth Code: " + responseFields.get(38));
        System.out.println("STAN: " + responseFields.get(11));
        
        System.out.println("[SUCCESS] SIMULATED TRANSACTION APPROVED");
        System.out.println("Note: This is a simulated response for testing purposes");
    }
}