import cron from 'node-cron'
import { ASNSampler } from './sampler'
import { ASPACollector } from './collector'
import { AdoptionAggregator } from './aggregator'
import { AdoptionForecaster } from './forecaster'
import { ASPADatabaseClient } from './db-client'

export class ASPAAdoptionScheduler {
  private task: cron.ScheduledTask | null = null
  private sampler = new ASNSampler()
  private collector = new ASPACollector()
  private aggregator = new AdoptionAggregator()
  private forecaster = new AdoptionForecaster()
  private dbClient = new ASPADatabaseClient()
  private isRunning = false

  /**
   * Start the daily ASPA adoption sampling job
   * Runs at 2 AM UTC every day (0 2 * * *)
   */
  start(): void {
    if (this.task) {
      console.log('[ASPA Scheduler] Job already scheduled')
      return
    }

    this.task = cron.schedule('0 2 * * *', () => {
      if (!this.isRunning) {
        this.runDailyJob().catch((error) => {
          console.error('[ASPA Scheduler] Daily job failed:', error)
        })
      }
    })

    console.log('[ASPA Scheduler] Scheduled daily job at 2:00 AM UTC')
  }

  /**
   * Stop the scheduled job
   */
  stop(): void {
    if (this.task) {
      this.task.stop()
      this.task.destroy()
      this.task = null
      console.log('[ASPA Scheduler] Job stopped')
    }
  }

  /**
   * Manually trigger the daily job (useful for testing)
   */
  async runManual(): Promise<void> {
    if (this.isRunning) {
      throw new Error('Job is already running')
    }

    await this.runDailyJob()
  }

  private async runDailyJob(): Promise<void> {
    this.isRunning = true
    const startTime = Date.now()

    try {
      console.log('[ASPA Scheduler] Starting daily adoption snapshot')

      const sampleDate = new Date()
      sampleDate.setUTCHours(0, 0, 0, 0)

      // Step 1: Stratified sample of ASNs
      console.log('[ASPA Scheduler] Sampling ASNs...')
      const samplingResult = this.sampler.sample(750, {
        stratifiedByRegion: true,
        minASNsPerRegion: 100,
      })
      console.log(`[ASPA Scheduler] Sampled ${samplingResult.totalSampled} ASNs`)

      // Step 2: Collect ASPA data for sampled ASNs
      console.log('[ASPA Scheduler] Collecting ASPA data...')
      const snapshots = await this.collector.collect(samplingResult.asns, {
        maxRetries: 3,
        timeoutMs: 5000,
        rateLimit: 100,
      })
      console.log(`[ASPA Scheduler] Collected ASPA data for ${snapshots.length} ASNs`)

      // Step 3: Aggregate by region and IXP
      console.log('[ASPA Scheduler] Aggregating data by region and IXP...')
      const { overall, regions, ixps } = this.aggregator.aggregate(snapshots, {
        includeRegions: true,
        includeIXPs: true,
      })
      console.log(
        `[ASPA Scheduler] Aggregation complete: ${overall.withASPA}/${overall.total} ASNs with ASPA (${overall.coverage}%)`
      )

      // Step 4: Fetch historical data and forecast
      console.log('[ASPA Scheduler] Calculating forecast...')
      const history = await this.dbClient.getAdoptionHistory(90)
      const timeSeriesData = history
        .reverse()
        .map((h) => ({
          date: h.sampleDate,
          coverage: h.coveragePercentage,
        }))
      const forecast = this.forecaster.forecast(timeSeriesData, {
        historyDays: 90,
        forecastMonths: 6,
        regressionAlpha: 0.05,
      })
      console.log(`[ASPA Scheduler] Forecast: ${forecast.predictedCoverage6m}% coverage in 6 months (confidence: ${forecast.confidence})`)

      // Step 5: Store results in database
      console.log('[ASPA Scheduler] Storing results...')
      const topAdopters = snapshots
        .filter((s) => s.hasASPA)
        .sort((a, b) => b.providers.length - a.providers.length)
        .slice(0, 10)
        .map((s) => ({
          asn: s.asn,
          name: `AS${s.asn}`,
          providers: s.providers.length,
        }))

      const metadata = {
        samplingMethod: 'stratified-regional',
        forecastData: forecast,
        dataCollectionTimeMs: Date.now() - startTime,
      }

      await this.dbClient.recordAdoptionSnapshot(sampleDate, overall.total, overall.withASPA, regions, topAdopters, metadata)
      await this.dbClient.recordRegionalBreakdown(sampleDate, regions)
      await this.dbClient.recordIXPBreakdown(sampleDate, ixps)

      console.log(`[ASPA Scheduler] Daily job completed in ${Date.now() - startTime}ms`)
    } catch (error) {
      console.error('[ASPA Scheduler] Job failed:', error instanceof Error ? error.message : String(error))
      throw error
    } finally {
      this.isRunning = false
    }
  }

  isJobRunning(): boolean {
    return this.isRunning
  }

  isScheduled(): boolean {
    return this.task !== null
  }
}

export const aspaScheduler = new ASPAAdoptionScheduler()
