import axios, { AxiosInstance, AxiosError } from 'axios'
import type { 
  PanelConfig, 
  PanelIpPool, 
  BurnVote, 
  HeartbeatStats,
  HeartbeatResponse,
  PanelIpInfo 
} from '../../shared/types'

// Rate limiting state
interface RateLimitState {
  isLimited: boolean
  retryAfter: number
  lastLimitTime: number
}

export class PanelService {
  private config: PanelConfig
  private client: AxiosInstance | null = null
  private rateLimitState: RateLimitState = {
    isLimited: false,
    retryAfter: 0,
    lastLimitTime: 0
  }

  constructor(config: PanelConfig) {
    this.config = config
    this.initializeClient()
  }

  updateConfig(config: PanelConfig): void {
    this.config = config
    this.initializeClient()
  }

  private initializeClient(): void {
    if (!this.config.apiUrl) {
      this.client = null
      return
    }

    this.client = axios.create({
      baseURL: this.config.apiUrl,
      timeout: 10000,
      headers: {
        'Content-Type': 'application/json',
        // API v1.1: Token is now 64-char hex from admin panel
        ...(this.config.authToken && {
          'Authorization': `Bearer ${this.config.authToken}`
        })
      }
    })

    // Add response interceptor for rate limiting
    this.client.interceptors.response.use(
      response => response,
      async (error: AxiosError) => {
        if (error.response?.status === 429) {
          const retryAfter = parseInt(error.response.headers['retry-after'] || '60', 10)
          this.rateLimitState = {
            isLimited: true,
            retryAfter,
            lastLimitTime: Date.now()
          }
          console.warn(`[PanelService] Rate limited. Retry after ${retryAfter}s`)
        }
        throw error
      }
    )
  }

  /**
   * @deprecated API v1.1: Token is now created via admin panel
   * This method is kept for backwards compatibility but will log a warning
   */
  async register(): Promise<{ success: boolean; authToken?: string; error?: string }> {
    console.warn('[PanelService] register() is deprecated in API v1.1. Token should be created via admin panel.')
    
    if (!this.client) {
      return { success: false, error: 'Panel not configured' }
    }

    try {
      const os = await import('os')
      const response = await this.client.post('/api.php?endpoint=servers', {
        server_id: this.config.monitorId,
        server_type: 'monitor',
        hostname: os.hostname(),
        ip_address: await this.getLocalIp(),
        country_code: 'TR'
      })

      if (response.data.success) {
        return {
          success: true,
          authToken: response.data.auth_token
        }
      }

      return { success: false, error: response.data.message }
    } catch (error) {
      return { success: false, error: (error as Error).message }
    }
  }

  /**
   * Get IP pool from panel
   * API v1.1: Changed endpoint from ip-pool to servers&for_monitor=1
   */
  async getIpPool(): Promise<PanelIpPool> {
    if (!this.client || !this.config.enabled) {
      return { ips: [], timestamp: Date.now() }
    }

    // Check rate limit
    if (this.isRateLimited()) {
      console.warn('[PanelService] Rate limited, skipping getIpPool')
      return { ips: [], timestamp: Date.now() }
    }

    try {
      // API v1.1: New endpoint
      const response = await this.client.get('/api.php', {
        params: {
          endpoint: 'servers',
          for_monitor: '1'
        }
      })

      // API v1.1: New response format
      if (response.data.ips) {
        return {
          ips: response.data.ips as PanelIpInfo[],
          timestamp: response.data.timestamp || Date.now()
        }
      }

      // Legacy format support
      if (response.data.success && response.data.ips) {
        const legacyIps = response.data.ips
        return {
          ips: [...(legacyIps.active || []), ...(legacyIps.honeypot || [])],
          timestamp: response.data.timestamp || Date.now(),
          active: legacyIps.active,
          honeypot: legacyIps.honeypot
        }
      }

      console.error('[PanelService] Failed to get IP pool:', response.data.message)
      return { ips: [], timestamp: Date.now() }
    } catch (error) {
      if ((error as AxiosError).response?.status !== 429) {
        console.error('[PanelService] Failed to fetch IP pool:', error)
      }
      return { ips: [], timestamp: Date.now() }
    }
  }

  /**
   * Send burn vote
   * API v1.1: monitor_id removed from payload (extracted from Bearer token)
   * API v1.1: reason field removed, evidence format changed
   */
  async sendBurnVote(vote: BurnVote): Promise<{ success: boolean; error?: string; currentVotes?: object }> {
    if (!this.client || !this.config.enabled) {
      return { success: false, error: 'Panel not enabled' }
    }

    // Check rate limit
    if (this.isRateLimited()) {
      console.warn('[PanelService] Rate limited, queuing burn vote')
      return { success: false, error: 'Rate limited, try again later' }
    }

    try {
      // API v1.1: New payload format - no monitor_id, no reason
      const response = await this.client.post('/api.php?endpoint=burn-vote', {
        ip_address: vote.ip_address,
        vote: vote.vote,
        evidence: vote.evidence
      })

      if (response.data.success) {
        console.log('[PanelService] Burn vote submitted:', {
          ip: vote.ip_address,
          vote: vote.vote,
          current_votes: response.data.current_votes
        })
        return { 
          success: true,
          currentVotes: response.data.current_votes
        }
      }

      return { success: false, error: response.data.message }
    } catch (error) {
      const axiosError = error as AxiosError
      
      // Handle 403 - wrong server type
      if (axiosError.response?.status === 403) {
        const errorData = axiosError.response.data as { message?: string }
        console.error('[PanelService] Forbidden:', errorData.message)
        return { success: false, error: errorData.message || 'Forbidden: Server type not allowed' }
      }

      // Retry on rate limit
      if (axiosError.response?.status === 429) {
        const retryAfter = parseInt(axiosError.response.headers['retry-after'] || '60', 10)
        console.warn(`[PanelService] Rate limited on burn vote. Waiting ${retryAfter}s...`)
        
        // Wait and retry once
        await this.sleep(retryAfter * 1000)
        return this.sendBurnVote(vote)
      }

      return { success: false, error: (error as Error).message }
    }
  }

  /**
   * Send heartbeat to panel
   * API v1.1: New endpoint for monitor liveness
   */
  async sendHeartbeat(stats: HeartbeatStats): Promise<HeartbeatResponse> {
    if (!this.client || !this.config.enabled) {
      return { success: false, message: 'Panel not enabled' }
    }

    // Check rate limit
    if (this.isRateLimited()) {
      return { success: false, message: 'Rate limited' }
    }

    try {
      const response = await this.client.post(
        '/api.php?endpoint=gateway-sync&action=heartbeat',
        { data: stats }
      )

      if (response.data.success) {
        console.log('[PanelService] Heartbeat sent successfully')
        return { success: true, message: response.data.message || 'Heartbeat received' }
      }

      return { success: false, message: response.data.message || 'Heartbeat failed' }
    } catch (error) {
      console.error('[PanelService] Heartbeat failed:', error)
      return { success: false, message: (error as Error).message }
    }
  }

  /**
   * Report IP health status - updated for API v1.1
   */
  async reportHealth(
    ipAddress: string,
    isWorking: boolean,
    checkResult: {
      checkType: 'http_health' | 'tcp_connect' | 'ssl_verify' | 'dns_lookup'
      responseCode?: number
      latencyMs?: number
      error?: string
    }
  ): Promise<void> {
    // API v1.1: New evidence format with checked_at ISO timestamp
    const vote: BurnVote = {
      ip_address: ipAddress,
      vote: isWorking ? 'ok' : 'burn',
      evidence: {
        check_type: checkResult.checkType,
        response_code: checkResult.responseCode || 0,
        latency_ms: checkResult.latencyMs || 0,
        error_message: checkResult.error || null,
        checked_at: new Date().toISOString()
      }
    }

    await this.sendBurnVote(vote)
  }

  /**
   * Check if currently rate limited
   */
  private isRateLimited(): boolean {
    if (!this.rateLimitState.isLimited) {
      return false
    }

    const elapsed = (Date.now() - this.rateLimitState.lastLimitTime) / 1000
    if (elapsed >= this.rateLimitState.retryAfter) {
      this.rateLimitState.isLimited = false
      return false
    }

    return true
  }

  /**
   * Sleep utility for retry logic
   */
  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms))
  }

  /**
   * Get local IP address
   */
  private async getLocalIp(): Promise<string> {
    const os = await import('os')
    const interfaces = os.networkInterfaces()
    
    for (const name of Object.keys(interfaces)) {
      for (const iface of interfaces[name] || []) {
        if (iface.family === 'IPv4' && !iface.internal) {
          return iface.address
        }
      }
    }
    
    return '127.0.0.1'
  }

  /**
   * Check if panel is configured and enabled
   */
  isEnabled(): boolean {
    return this.config.enabled && !!this.config.apiUrl && !!this.config.authToken
  }

  /**
   * Get rate limit status for UI display
   */
  getRateLimitStatus(): { isLimited: boolean; secondsRemaining: number } {
    if (!this.rateLimitState.isLimited) {
      return { isLimited: false, secondsRemaining: 0 }
    }

    const elapsed = (Date.now() - this.rateLimitState.lastLimitTime) / 1000
    const remaining = Math.max(0, this.rateLimitState.retryAfter - elapsed)
    
    return {
      isLimited: remaining > 0,
      secondsRemaining: Math.ceil(remaining)
    }
  }
}
