/**
 * Integration test for multi-platform signing
 *
 * This test verifies the complete multi-platform signing workflow:
 * 1. Load configuration with accounts from different platforms
 * 2. Perform signing operations using platform-specific algorithms
 * 3. Verify signatures using platform-specific verification
 * 4. Test cross-platform compatibility and isolation
 *
 * Platforms tested:
 * - Pacifica (Ed25519)
 * - Aster (EIP-191)
 * - Binance (HMAC-SHA256)
 *
 * Tests MUST FAIL initially until implementation is provided.
 */

import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';

// Import types (this import will fail until types are implemented)
import type {
  ICredentialManager,
  SignResult,
  Account,
  Platform,
  ConfigFile
} from '@/specs/001-credential-manager/contracts/credential-manager';

describe('Multi-Platform Signing Integration Tests', () => {
  let credentialManager: ICredentialManager;
  let tempDir: string;
  let configPath: string;

  // Test messages for different platforms
  const testMessages = {
    pacifica: new TextEncoder().encode(JSON.stringify({
      order_type: 'market',
      symbol: 'BTC-USD',
      side: 'buy',
      size: '0.1',
      timestamp: Date.now()
    })),
    aster: new TextEncoder().encode('Transfer 100 ETH to 0x1234567890abcdef'),
    binance: new TextEncoder().encode('GET\n/api/v3/account\n\ntimestamp=1234567890000')
  };

  beforeEach(async () => {
    // This will fail until CredentialManager is implemented
    const { CredentialManager } = await import('@/core/credential-manager/CredentialManager');
    credentialManager = new CredentialManager();

    // Create temporary directory
    tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'multi-platform-test-'));
    configPath = path.join(tempDir, 'multi-platform-config.json');

    // Create multi-platform configuration
    const multiPlatformConfig: ConfigFile = {
      version: "1.0",
      accounts: [
        {
          id: "pacifica-test-account",
          platform: Platform.PACIFICA,
          name: "Pacifica Trading Account",
          credentials: {
            type: "ed25519",
            privateKey: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
          }
        },
        {
          id: "aster-test-account",
          platform: Platform.ASTER,
          name: "Aster DeFi Account",
          credentials: {
            type: "eip191",
            privateKey: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
          }
        },
        {
          id: "binance-test-account",
          platform: Platform.BINANCE,
          name: "Binance Spot Account",
          credentials: {
            type: "hmac",
            apiKey: "test-binance-api-key",
            secretKey: "test-binance-secret-key"
          }
        }
      ]
    };

    await fs.writeFile(configPath, JSON.stringify(multiPlatformConfig, null, 2));
    await credentialManager.loadConfig(configPath);
  });

  afterEach(async () => {
    // Clean up
    credentialManager.stopWatching();

    try {
      await fs.rm(tempDir, { recursive: true, force: true });
    } catch (error) {
      // Ignore cleanup errors
    }
  });

  describe('Platform Account Loading', () => {
    test('should load accounts from all supported platforms', () => {
      // Act
      const allAccounts = credentialManager.listAccounts();

      // Assert
      expect(allAccounts).toHaveLength(3);

      const platforms = allAccounts.map(account => account.platform);
      expect(platforms).toContain(Platform.PACIFICA);
      expect(platforms).toContain(Platform.ASTER);
      expect(platforms).toContain(Platform.BINANCE);
    });

    test('should retrieve specific accounts by ID', () => {
      // Act & Assert
      const pacificaAccount = credentialManager.getAccount("pacifica-test-account");
      expect(pacificaAccount).not.toBeNull();
      expect(pacificaAccount!.platform).toBe(Platform.PACIFICA);
      expect(pacificaAccount!.credentials.type).toBe("ed25519");

      const asterAccount = credentialManager.getAccount("aster-test-account");
      expect(asterAccount).not.toBeNull();
      expect(asterAccount!.platform).toBe(Platform.ASTER);
      expect(asterAccount!.credentials.type).toBe("eip191");

      const binanceAccount = credentialManager.getAccount("binance-test-account");
      expect(binanceAccount).not.toBeNull();
      expect(binanceAccount!.platform).toBe(Platform.BINANCE);
      expect(binanceAccount!.credentials.type).toBe("hmac");
    });
  });

  describe('Pacifica (Ed25519) Signing', () => {
    test('should sign Pacifica order message successfully', async () => {
      // Act
      const result: SignResult = await credentialManager.sign(
        "pacifica-test-account",
        testMessages.pacifica
      );

      // Assert
      expect(result.success).toBe(true);
      expect(result.algorithm).toBe('ed25519');
      expect(typeof result.signature).toBe('string');
      expect(result.signature!.length).toBe(88); // base64 encoded Ed25519 signature
      expect(result.timestamp).toBeInstanceOf(Date);
    });

    test('should verify Pacifica signature correctly', async () => {
      // Arrange - create signature
      const signResult = await credentialManager.sign(
        "pacifica-test-account",
        testMessages.pacifica
      );
      expect(signResult.success).toBe(true);

      // Act - verify signature
      const isValid = await credentialManager.verify(
        "pacifica-test-account",
        testMessages.pacifica,
        signResult.signature!
      );

      // Assert
      expect(isValid).toBe(true);
    });

    test('should reject invalid Pacifica signature', async () => {
      // Act - verify invalid signature
      const isValid = await credentialManager.verify(
        "pacifica-test-account",
        testMessages.pacifica,
        "invalid-signature"
      );

      // Assert
      expect(isValid).toBe(false);
    });
  });

  describe('Aster (EIP-191) Signing', () => {
    test('should sign Aster message successfully', async () => {
      // Act
      const result: SignResult = await credentialManager.sign(
        "aster-test-account",
        testMessages.aster
      );

      // Assert
      expect(result.success).toBe(true);
      expect(result.algorithm).toBe('eip191');
      expect(typeof result.signature).toBe('string');
      expect(result.signature!.startsWith('0x')).toBe(true); // Ethereum-style signature
      expect(result.signature!.length).toBe(132); // 0x + 130 hex chars for EIP-191
    });

    test('should verify Aster signature correctly', async () => {
      // Arrange
      const signResult = await credentialManager.sign(
        "aster-test-account",
        testMessages.aster
      );
      expect(signResult.success).toBe(true);

      // Act
      const isValid = await credentialManager.verify(
        "aster-test-account",
        testMessages.aster,
        signResult.signature!
      );

      // Assert
      expect(isValid).toBe(true);
    });

    test('should handle Ethereum personal message prefix', async () => {
      // Arrange - message that requires Ethereum personal message prefix
      const personalMessage = new TextEncoder().encode("Hello, Ethereum!");

      // Act
      const result = await credentialManager.sign(
        "aster-test-account",
        personalMessage
      );

      // Assert
      expect(result.success).toBe(true);
      expect(result.algorithm).toBe('eip191');

      // Verify the signature
      const isValid = await credentialManager.verify(
        "aster-test-account",
        personalMessage,
        result.signature!
      );
      expect(isValid).toBe(true);
    });
  });

  describe('Binance (HMAC-SHA256) Signing', () => {
    test('should sign Binance API request successfully', async () => {
      // Act
      const result: SignResult = await credentialManager.sign(
        "binance-test-account",
        testMessages.binance
      );

      // Assert
      expect(result.success).toBe(true);
      expect(result.algorithm).toBe('hmac-sha256');
      expect(typeof result.signature).toBe('string');
      expect(result.signature!.length).toBe(64); // HMAC-SHA256 produces 64 hex chars
    });

    test('should verify Binance signature correctly', async () => {
      // Arrange
      const signResult = await credentialManager.sign(
        "binance-test-account",
        testMessages.binance
      );
      expect(signResult.success).toBe(true);

      // Act
      const isValid = await credentialManager.verify(
        "binance-test-account",
        testMessages.binance,
        signResult.signature!
      );

      // Assert
      expect(isValid).toBe(true);
    });

    test('should handle Binance API query string format', async () => {
      // Arrange - typical Binance API query string
      const queryString = "symbol=BTCUSDT&side=BUY&type=MARKET&quantity=0.1&timestamp=1234567890000";
      const queryMessage = new TextEncoder().encode(queryString);

      // Act
      const result = await credentialManager.sign(
        "binance-test-account",
        queryMessage
      );

      // Assert
      expect(result.success).toBe(true);
      expect(result.algorithm).toBe('hmac-sha256');

      // Verify signature
      const isValid = await credentialManager.verify(
        "binance-test-account",
        queryMessage,
        result.signature!
      );
      expect(isValid).toBe(true);
    });
  });

  describe('Cross-Platform Isolation', () => {
    test('should not allow signing with wrong platform account', async () => {
      // Act & Assert - try to sign Pacifica message with Binance account
      const result = await credentialManager.sign(
        "binance-test-account",
        testMessages.pacifica
      );

      // Should either fail or produce platform-appropriate signature
      if (result.success) {
        expect(result.algorithm).toBe('hmac-sha256'); // Should use Binance algorithm
      } else {
        expect(typeof result.error).toBe('string');
      }
    });

    test('should maintain signature isolation between platforms', async () => {
      // Arrange - same message signed by different platforms
      const commonMessage = new TextEncoder().encode("Common test message");

      // Act - sign with all platforms
      const pacificaResult = await credentialManager.sign("pacifica-test-account", commonMessage);
      const asterResult = await credentialManager.sign("aster-test-account", commonMessage);
      const binanceResult = await credentialManager.sign("binance-test-account", commonMessage);

      // Assert - all should succeed but with different signatures
      expect(pacificaResult.success).toBe(true);
      expect(asterResult.success).toBe(true);
      expect(binanceResult.success).toBe(true);

      expect(pacificaResult.algorithm).toBe('ed25519');
      expect(asterResult.algorithm).toBe('eip191');
      expect(binanceResult.algorithm).toBe('hmac-sha256');

      // Signatures should be different
      expect(pacificaResult.signature).not.toBe(asterResult.signature);
      expect(asterResult.signature).not.toBe(binanceResult.signature);
      expect(pacificaResult.signature).not.toBe(binanceResult.signature);
    });

    test('should reject cross-platform signature verification', async () => {
      // Arrange - sign with one platform
      const message = new TextEncoder().encode("Cross-platform test");
      const pacificaResult = await credentialManager.sign("pacifica-test-account", message);
      expect(pacificaResult.success).toBe(true);

      // Act - try to verify with different platform account
      const isValid = await credentialManager.verify(
        "aster-test-account",  // Different platform
        message,
        pacificaResult.signature!
      );

      // Assert - should fail verification
      expect(isValid).toBe(false);
    });
  });

  describe('Concurrent Multi-Platform Operations', () => {
    test('should handle concurrent signing across platforms', async () => {
      // Arrange
      const concurrentOperations = [
        credentialManager.sign("pacifica-test-account", testMessages.pacifica),
        credentialManager.sign("aster-test-account", testMessages.aster),
        credentialManager.sign("binance-test-account", testMessages.binance),
        credentialManager.sign("pacifica-test-account", new TextEncoder().encode("Second Pacifica")),
        credentialManager.sign("aster-test-account", new TextEncoder().encode("Second Aster"))
      ];

      // Act
      const results = await Promise.all(concurrentOperations);

      // Assert - all operations should complete successfully
      results.forEach((result, index) => {
        expect(result.success).toBe(true);
        expect(typeof result.signature).toBe('string');
      });

      // Verify algorithms are correct
      expect(results[0].algorithm).toBe('ed25519');  // Pacifica
      expect(results[1].algorithm).toBe('eip191');   // Aster
      expect(results[2].algorithm).toBe('hmac-sha256'); // Binance
      expect(results[3].algorithm).toBe('ed25519');  // Pacifica again
      expect(results[4].algorithm).toBe('eip191');   // Aster again
    });

    test('should maintain performance across all platforms', async () => {
      // Performance requirement: signing < 50ms per operation
      const performanceTests = [
        { platform: "pacifica-test-account", message: testMessages.pacifica },
        { platform: "aster-test-account", message: testMessages.aster },
        { platform: "binance-test-account", message: testMessages.binance }
      ];

      for (const test of performanceTests) {
        const startTime = Date.now();
        const result = await credentialManager.sign(test.platform, test.message);
        const duration = Date.now() - startTime;

        expect(result.success).toBe(true);
        expect(duration).toBeLessThan(50); // Performance requirement
      }
    });
  });

  describe('Platform-Specific Error Handling', () => {
    test('should handle Pacifica-specific errors gracefully', async () => {
      // Arrange - invalid Pacifica message (too large)
      const oversizedMessage = new Uint8Array(2 * 1024 * 1024); // 2MB

      // Act
      const result = await credentialManager.sign("pacifica-test-account", oversizedMessage);

      // Assert
      expect(result.success).toBe(false);
      expect(typeof result.error).toBe('string');
      expect(result.error!).toContain('size');
    });

    test('should handle Aster-specific errors gracefully', async () => {
      // Arrange - test with malformed Ethereum address format if applicable
      const asterAccount = credentialManager.getAccount("aster-test-account");
      expect(asterAccount).not.toBeNull();

      // Act - attempt operation that might cause Aster-specific error
      const result = await credentialManager.sign("aster-test-account", new Uint8Array(0));

      // Assert - should handle gracefully
      expect(typeof result.success).toBe('boolean');
      if (!result.success) {
        expect(typeof result.error).toBe('string');
      }
    });

    test('should handle Binance-specific errors gracefully', async () => {
      // Arrange - empty message which might be invalid for HMAC
      const emptyMessage = new Uint8Array(0);

      // Act
      const result = await credentialManager.sign("binance-test-account", emptyMessage);

      // Assert - should handle gracefully
      expect(typeof result.success).toBe('boolean');
      if (!result.success) {
        expect(typeof result.error).toBe('string');
      }
    });
  });

  describe('Platform Detection and Validation', () => {
    test('should correctly identify platform for each account', () => {
      // Act & Assert
      const accounts = credentialManager.listAccounts();

      accounts.forEach(account => {
        switch (account.platform) {
          case Platform.PACIFICA:
            expect(account.credentials.type).toBe('ed25519');
            expect(account.credentials.privateKey).toMatch(/^[0-9a-f]{64}$/);
            break;
          case Platform.ASTER:
            expect(account.credentials.type).toBe('eip191');
            expect(account.credentials.privateKey).toMatch(/^0x[0-9a-f]{64}$/);
            break;
          case Platform.BINANCE:
            expect(account.credentials.type).toBe('hmac');
            expect(account.credentials.apiKey).toBeTruthy();
            expect(account.credentials.secretKey).toBeTruthy();
            break;
          default:
            fail(`Unknown platform: ${account.platform}`);
        }
      });
    });

    test('should validate credential format for each platform', () => {
      // This test verifies that the credential manager validates
      // platform-specific credential formats during loading
      const accounts = credentialManager.listAccounts();
      expect(accounts).toHaveLength(3);

      // All accounts should be loaded successfully, indicating valid credential formats
      accounts.forEach(account => {
        expect(account.credentials).toBeDefined();
        expect(typeof account.credentials.type).toBe('string');
      });
    });
  });
});