/**
 * Simplified Authentication Manager
 *
 * Manages authentication for HTTP requests using AccountRegistry.
 * Provides direct signing without complex abstractions.
 */

import type { SignerFactory } from '@/core/credential-manager/SignerFactory'
import type { Platform, Credentials } from '@/types/credential'
import type { PlatformRequest, PreparedRequest } from '@/types/platformAdapter'
import type { AccountRegistry } from './AccountRegistry'

export interface AuthenticationContext {
  /** Account identifier */
  accountId: string

  /** Platform identifier */
  platform: string

  /** Authentication algorithm */
  algorithm: 'Ed25519' | 'HMAC-SHA256' | 'EIP-191'

  /** Whether authentication is required */
  requiresAuth: boolean

  /** Timestamp for authentication */
  timestamp?: number

  /** Nonce for authentication */
  nonce?: string
}

export interface SignatureResult {
  /** Generated signature */
  signature: string

  /** Signature algorithm used */
  algorithm: string

  /** Timestamp when signature was generated */
  timestamp: Date

  /** Additional signature metadata */
  metadata?: Record<string, any>
}

/**
 * Simplified Authentication Manager
 */
export class AuthenticationManager {
  constructor(
    private signerFactory: SignerFactory,
    private accountRegistry: AccountRegistry,
  ) {}

  /**
   * Create AuthenticationManager with SignerFactory and AccountRegistry
   */
  static create(signerFactory: SignerFactory, accountRegistry: AccountRegistry): AuthenticationManager {
    return new AuthenticationManager(signerFactory, accountRegistry)
  }

  /**
   * Create AuthenticationManager with just SignerFactory (for backward compatibility)
   */
  static createWithSignerFactory(signerFactory: SignerFactory): AuthenticationManager {
    // Import the global registry here to avoid circular dependencies
    const { globalAccountRegistry } = require('./AccountRegistry')
    return new AuthenticationManager(signerFactory, globalAccountRegistry)
  }

  /**
   * Prepare request with authentication
   */
  async prepareRequest(request: PlatformRequest, context: AuthenticationContext): Promise<PreparedRequest> {
    if (!context.requiresAuth) {
      return {
        ...request,
        headers: request.headers || {},
        authenticated: false,
      }
    }

    // Get credentials from registry
    const credentials = this.accountRegistry.getCredentials(context.platform, context.accountId)
    if (!credentials) {
      throw new Error(`No credentials found for account ${context.accountId} on platform ${context.platform}`)
    }

    // Sign the request using appropriate signer
    const signature = await this.signRequest(request, credentials, context)

    // Add authentication headers based on platform
    const authHeaders = this.buildAuthHeaders(signature, credentials, context)

    return {
      ...request,
      headers: {
        ...request.headers,
        ...authHeaders,
      },
      authenticated: true,
      signature: signature.signature,
      algorithm: signature.algorithm,
    }
  }

  /**
   * Sign request data
   */
  private async signRequest(
    request: PlatformRequest,
    credentials: Credentials,
    context: AuthenticationContext,
  ): Promise<SignatureResult> {
    // Convert platform string to Platform enum
    const platform = this.stringToPlatform(context.platform)

    // Get appropriate signer
    const signer = this.signerFactory.getSigner(platform)

    // Prepare data to sign based on platform
    const dataToSign = this.prepareSigningData(request, context)

    // Sign the data
    const signature = await signer.sign(dataToSign, credentials)

    return {
      signature,
      algorithm: context.algorithm,
      timestamp: new Date(),
      metadata: {
        platform: context.platform,
        accountId: context.accountId,
      },
    }
  }

  /**
   * Build authentication headers based on platform
   */
  private buildAuthHeaders(
    signature: SignatureResult,
    credentials: Credentials,
    context: AuthenticationContext,
  ): Record<string, string> {
    const headers: Record<string, string> = {}

    switch (context.platform) {
      case 'pacifica':
        headers['X-Signature'] = signature.signature
        if (context.timestamp) {
          headers['X-Timestamp'] = context.timestamp.toString()
        }
        break

      case 'binance':
        if (credentials.type === 'hmac' && credentials.apiKey) {
          headers['X-MBX-APIKEY'] = credentials.apiKey
        }
        headers['X-MBX-SIGNATURE'] = signature.signature
        if (context.timestamp) {
          headers['timestamp'] = context.timestamp.toString()
        }
        break

      case 'aster':
        headers['X-Signature'] = signature.signature
        if (context.timestamp) {
          headers['X-Timestamp'] = context.timestamp.toString()
        }
        break

      default:
        headers['Authorization'] = `Signature ${signature.signature}`
        break
    }

    return headers
  }

  /**
   * Prepare data for signing based on platform requirements
   */
  private prepareSigningData(request: PlatformRequest, context: AuthenticationContext): Uint8Array {
    let dataString = ''

    switch (context.platform) {
      case 'pacifica':
        // Pacifica signing format: method + path + timestamp + body
        dataString = [
          request.method,
          request.path,
          context.timestamp?.toString() || Date.now().toString(),
          request.body ? JSON.stringify(request.body) : '',
        ].join('')
        break

      case 'binance':
        // Binance signing format: query string
        const params = new URLSearchParams()
        if (request.params) {
          Object.entries(request.params).forEach(([key, value]) => {
            params.append(key, String(value))
          })
        }
        if (context.timestamp) {
          params.append('timestamp', context.timestamp.toString())
        }
        dataString = params.toString()
        break

      case 'aster':
        // Aster signing format: similar to Pacifica
        dataString = [
          request.method,
          request.path,
          context.timestamp?.toString() || Date.now().toString(),
          request.body ? JSON.stringify(request.body) : '',
        ].join('')
        break

      default:
        // Default: method + path + body
        dataString = [
          request.method,
          request.path,
          request.body ? JSON.stringify(request.body) : '',
        ].join('')
        break
    }

    return new TextEncoder().encode(dataString)
  }

  /**
   * Convert platform string to Platform enum
   */
  private stringToPlatform(platform: string): Platform {
    switch (platform.toLowerCase()) {
      case 'pacifica':
        return Platform.PACIFICA
      case 'binance':
        return Platform.BINANCE
      case 'aster':
        return Platform.ASTER
      default:
        throw new Error(`Unsupported platform: ${platform}`)
    }
  }

  /**
   * Check if account has credentials
   */
  hasCredentials(platform: string, accountId: string): boolean {
    return this.accountRegistry.hasAccount(platform, accountId)
  }

  /**
   * Set account registry (for dependency injection)
   */
  setAccountRegistry(accountRegistry: AccountRegistry): void {
    ;(this as any).accountRegistry = accountRegistry
  }

  /**
   * Set signer factory (for dependency injection)
   */
  setSignerFactory(signerFactory: SignerFactory): void {
    ;(this as any).signerFactory = signerFactory
  }
}

export default AuthenticationManager