import { query, queryOne, execute } from './db'

// 상수 정의
const INTERVAL_SUCCESS = 5 * 60 * 1000  // 5분
const INTERVAL_FAILURE = 1 * 60 * 1000  // 1분
const REQUEST_TIMEOUT = 10 * 1000       // 10초

// 타입 정의
interface PrivnetTarget {
  id: number
  name: string
  url: string
  is_active: number
}

interface PrivnetStatus {
  id: number
  current_index: number
  check_interval: number
  is_healthy: number
  last_target_id: number | null
  last_checked_at: string | null
  scheduler_running: number
}

interface CheckResult {
  targetId: number
  targetName: string
  url: string
  isSuccess: boolean
}

class PrivnetScheduler {
  private timer: ReturnType<typeof setTimeout> | null = null
  private isRunning: boolean = false

  /**
   * 스케줄러 시작
   */
  start(): void {
    if (this.isRunning) {
      console.log('[PrivnetScheduler] Already running')
      return
    }

    this.isRunning = true
    this.updateSchedulerRunning(1)
    console.log('[PrivnetScheduler] Started')
    
    // 즉시 첫 체크 실행
    this.runCheck()
  }

  /**
   * 스케줄러 중지
   */
  stop(): void {
    if (this.timer) {
      clearTimeout(this.timer)
      this.timer = null
    }
    this.isRunning = false
    this.updateSchedulerRunning(0)
    console.log('[PrivnetScheduler] Stopped')
  }

  /**
   * 실행 상태 확인
   */
  getIsRunning(): boolean {
    return this.isRunning
  }

  /**
   * 체크 실행
   */
  private async runCheck(): Promise<void> {
    if (!this.isRunning) return

    try {
      const result = await this.checkCurrentTarget()
      
      // 결과에 따라 다음 간격 결정
      const nextInterval = result.isSuccess ? INTERVAL_SUCCESS : INTERVAL_FAILURE
      
      // 로그 저장
      await this.saveLog(result)
      
      // 상태 업데이트 (인덱스 증가)
      await this.updateStatus(result, nextInterval)
      
      console.log(
        `[PrivnetScheduler] ${result.targetName} (${result.url}) - ` +
        `${result.isSuccess ? 'SUCCESS' : 'FAILED'} - ` +
        `Next check in ${nextInterval / 1000}s`
      )

      // 다음 체크 예약
      this.timer = setTimeout(() => this.runCheck(), nextInterval)
      
    } catch (error) {
      console.error('[PrivnetScheduler] Error:', error)
      // 에러 발생 시 1분 후 재시도
      this.timer = setTimeout(() => this.runCheck(), INTERVAL_FAILURE)
    }
  }

  /**
   * 현재 타겟 URL 체크
   */
  private async checkCurrentTarget(): Promise<CheckResult> {
    // 활성화된 타겟 목록 조회
    const targets = await query<PrivnetTarget>(`
      SELECT * FROM privnet_targets 
      WHERE is_active = 1 
      ORDER BY id ASC
    `)

    if (targets.length === 0) {
      throw new Error('No active targets found')
    }

    // 현재 인덱스 조회
    const status = await queryOne<PrivnetStatus>('SELECT * FROM privnet_status WHERE id = 1')
    if (!status) {
      throw new Error('Status not found')
    }
    
    const currentIndex = status.current_index % targets.length
    const target = targets[currentIndex]

    // HTTP 요청 실행
    let isSuccess = false

    try {
      const controller = new AbortController()
      const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT)

      const response = await fetch(target.url, {
        method: 'HEAD',
        signal: controller.signal,
        headers: {
          'User-Agent': 'OSOLIT-Monitor/1.0'
        }
      })

      clearTimeout(timeoutId)
      isSuccess = response.status === 200

    } catch (err: any) {
      isSuccess = false
    }

    return {
      targetId: target.id,
      targetName: target.name,
      url: target.url,
      isSuccess
    }
  }

  /**
   * 체크 결과 로그 저장
   */
  private async saveLog(result: CheckResult): Promise<void> {
    await execute(
      `INSERT INTO privnet_logs (target_id, is_success) VALUES ($1, $2)`,
      [result.targetId, result.isSuccess ? 1 : 0]
    )
  }

  /**
   * 상태 업데이트 (인덱스 순환)
   */
  private async updateStatus(result: CheckResult, nextInterval: number): Promise<void> {
    // 활성 타겟 수 조회
    const countResult = await queryOne<{ cnt: string }>(
      `SELECT COUNT(*) as cnt FROM privnet_targets WHERE is_active = 1`
    )
    const totalCount = parseInt(countResult?.cnt || '0')
    
    const status = await queryOne<{ current_index: number }>(
      'SELECT current_index FROM privnet_status WHERE id = 1'
    )
    const nextIndex = ((status?.current_index || 0) + 1) % totalCount

    await execute(`
      UPDATE privnet_status SET
        current_index = $1,
        check_interval = $2,
        is_healthy = $3,
        last_target_id = $4,
        last_checked_at = to_char(NOW(), 'YYYY-MM-DD HH24:MI:SS'),
        updated_at = to_char(NOW(), 'YYYY-MM-DD HH24:MI:SS')
      WHERE id = 1
    `, [nextIndex, nextInterval, result.isSuccess ? 1 : 0, result.targetId])
  }

  /**
   * 스케줄러 실행 상태 업데이트
   */
  private async updateSchedulerRunning(running: number): Promise<void> {
    await execute(`
      UPDATE privnet_status SET 
        scheduler_running = $1,
        updated_at = to_char(NOW(), 'YYYY-MM-DD HH24:MI:SS')
      WHERE id = 1
    `, [running])
  }
}

// 싱글톤 인스턴스
export const privnetScheduler = new PrivnetScheduler()
