/**
 * Automation Worker Service
 *
 * Central state machine for order automation. Handles automatic transitions
 * between order statuses based on automation mode.
 *
 * Automation Modes:
 * - AUTO: Self-executing (website orders) - triggers next step automatically
 * - MANUAL: Step-by-step (staff orders) - requires manual button clicks
 * - PAUSED: Stopped for intervention - resumes when staff acts
 *
 * Status Flow:
 * PAYMENT_CONFIRMED → AWAITING_SERVER → SERVER_READY → DNS_PENDING → DNS_READY → PROVISIONING → FULFILLED
 */

import { prisma } from '@/lib/prisma'
import { OrderStatus, AutomationMode, LogLevel } from '@prisma/client'

export interface AutomationResult {
  triggered: boolean
  action?: string
  error?: string
}

/**
 * Log an automation event to the provisioning logs
 */
async function logAutomation(
  orderId: string,
  level: LogLevel,
  message: string,
  step: string = 'automation'
): Promise<void> {
  try {
    await prisma.provisioningLog.create({
      data: {
        orderId,
        level,
        message,
        step,
      },
    })
  } catch (error) {
    console.error('Failed to log automation event:', error)
  }
}

/**
 * Process automation for an order after any status change.
 *
 * This should be called after:
 * - Order PATCH (credentials saved, status change)
 * - DNS verification complete
 * - Provisioning job status update
 *
 * In AUTO mode, this triggers the next step automatically.
 * In MANUAL mode, this does nothing (user must click buttons).
 * In PAUSED mode, this does nothing until resumed.
 */
export async function processAutomation(orderId: string): Promise<AutomationResult> {
  const order = await prisma.order.findUnique({
    where: { id: orderId },
    include: {
      dnsVerification: true,
      serverConnection: true,
    },
  })

  if (!order) {
    return { triggered: false, error: 'Order not found' }
  }

  // Only process if automation mode is AUTO
  if (order.automationMode !== AutomationMode.AUTO) {
    return { triggered: false, action: `Skipped: mode is ${order.automationMode}` }
  }

  // State machine based on current status
  switch (order.status) {
    case OrderStatus.PAYMENT_CONFIRMED:
      // Waiting for initial processing - no automation here
      return { triggered: false, action: 'Waiting for AWAITING_SERVER' }

    case OrderStatus.AWAITING_SERVER:
      // Check if credentials are now available
      if (order.serverIp && order.serverPasswordEncrypted) {
        // Transition to SERVER_READY
        await prisma.order.update({
          where: { id: orderId },
          data: {
            status: OrderStatus.SERVER_READY,
            serverReadyAt: new Date(),
          },
        })
        await logAutomation(orderId, LogLevel.INFO, 'Auto-transitioned to SERVER_READY (credentials configured)')

        // Recursively process to continue automation
        return processAutomation(orderId)
      }
      return { triggered: false, action: 'Waiting for server credentials' }

    case OrderStatus.SERVER_READY:
      // Auto-transition to DNS_PENDING and trigger DNS verification
      await prisma.order.update({
        where: { id: orderId },
        data: {
          status: OrderStatus.DNS_PENDING,
        },
      })
      await logAutomation(orderId, LogLevel.INFO, 'Auto-transitioned to DNS_PENDING, initiating DNS verification')

      // Note: The actual DNS verification will be triggered by the frontend
      // or can be called directly via triggerDnsVerification()
      return { triggered: true, action: 'Transitioned to DNS_PENDING' }

    case OrderStatus.DNS_PENDING:
      // Check if DNS verification passed
      if (order.dnsVerification?.allPassed || order.dnsVerification?.manualOverride) {
        await prisma.order.update({
          where: { id: orderId },
          data: {
            status: OrderStatus.DNS_READY,
            dnsVerifiedAt: new Date(),
          },
        })
        await logAutomation(orderId, LogLevel.INFO, 'Auto-transitioned to DNS_READY (verification passed)')

        // Recursively process to continue automation
        return processAutomation(orderId)
      }
      return { triggered: false, action: 'Waiting for DNS verification' }

    case OrderStatus.DNS_READY:
      // Auto-trigger provisioning
      await logAutomation(orderId, LogLevel.INFO, 'Auto-triggering provisioning')

      // Note: The actual provisioning will be triggered by calling the provision endpoint
      // This is because provisioning requires spawning a Docker container
      return { triggered: true, action: 'Ready for provisioning - trigger provision endpoint' }

    case OrderStatus.PROVISIONING:
      // Provisioning in progress - no action needed
      return { triggered: false, action: 'Provisioning in progress' }

    case OrderStatus.FULFILLED:
      // Order complete - no action needed
      return { triggered: false, action: 'Order fulfilled' }

    case OrderStatus.FAILED:
      // Auto-pause on failure
      if (order.automationMode === AutomationMode.AUTO) {
        await prisma.order.update({
          where: { id: orderId },
          data: {
            automationMode: AutomationMode.PAUSED,
            automationPausedAt: new Date(),
            automationPausedReason: 'FAILED - requires manual intervention',
          },
        })
        await logAutomation(orderId, LogLevel.WARN, 'Automation paused due to failure')
        return { triggered: true, action: 'Paused automation due to failure' }
      }
      return { triggered: false, action: 'Order failed - manual intervention required' }

    default:
      return { triggered: false, action: `Unknown status: ${order.status}` }
  }
}

/**
 * Change automation mode for an order
 */
export async function setAutomationMode(
  orderId: string,
  mode: AutomationMode,
  reason?: string
): Promise<void> {
  const updateData: {
    automationMode: AutomationMode
    automationPausedAt?: Date | null
    automationPausedReason?: string | null
  } = {
    automationMode: mode,
  }

  if (mode === AutomationMode.PAUSED) {
    updateData.automationPausedAt = new Date()
    updateData.automationPausedReason = reason || 'Manually paused'
  } else {
    // Clear pause info when resuming
    updateData.automationPausedAt = null
    updateData.automationPausedReason = null
  }

  await prisma.order.update({
    where: { id: orderId },
    data: updateData,
  })

  await logAutomation(
    orderId,
    LogLevel.INFO,
    `Automation mode changed to ${mode}${reason ? `: ${reason}` : ''}`
  )

  // If switching to AUTO, trigger processing
  if (mode === AutomationMode.AUTO) {
    await processAutomation(orderId)
  }
}

/**
 * Resume automation from PAUSED state
 */
export async function resumeAutomation(orderId: string): Promise<AutomationResult> {
  const order = await prisma.order.findUnique({
    where: { id: orderId },
  })

  if (!order) {
    return { triggered: false, error: 'Order not found' }
  }

  if (order.automationMode !== AutomationMode.PAUSED) {
    return { triggered: false, error: 'Order is not paused' }
  }

  // Switch to AUTO and process
  await setAutomationMode(orderId, AutomationMode.AUTO, 'Resumed by staff')

  return { triggered: true, action: 'Automation resumed' }
}

/**
 * Pause automation
 */
export async function pauseAutomation(orderId: string, reason?: string): Promise<void> {
  await setAutomationMode(orderId, AutomationMode.PAUSED, reason || 'Manually paused by staff')
}

/**
 * Take manual control of an order
 */
export async function takeManualControl(orderId: string): Promise<void> {
  await setAutomationMode(orderId, AutomationMode.MANUAL, 'Staff took manual control')
}

/**
 * Enable auto mode for an order
 */
export async function enableAutoMode(orderId: string): Promise<AutomationResult> {
  await setAutomationMode(orderId, AutomationMode.AUTO, 'Staff enabled auto mode')

  // Process automation immediately
  return processAutomation(orderId)
}
