import { NextRequest, NextResponse } from 'next/server'
import crypto from 'crypto'
import { auth } from '@/lib/auth'
import { requireStaffPermission } from '@/lib/auth-helpers'
import { prisma } from '@/lib/prisma'
import { OrderStatus } from '@prisma/client'
import { processAutomation } from '@/lib/services/automation-worker'
import { netcupService } from '@/lib/services/netcup-service'
import { runDnsVerification } from '@/lib/services/dns-service'
import { credentialService } from '@/lib/services/credential-service'

/**
 * GET /api/v1/admin/orders/[id]
 * Get order details
 */
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const session = await auth()

    if (!session || session.user.userType !== 'staff') {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { id: orderId } = await params

    const order = await prisma.order.findUnique({
      where: { id: orderId },
      include: {
        user: {
          select: {
            id: true,
            name: true,
            email: true,
            company: true,
          },
        },
        provisioningLogs: {
          orderBy: { timestamp: 'desc' },
          take: 100,
        },
        jobs: {
          orderBy: { createdAt: 'desc' },
          take: 5,
          select: {
            id: true,
            status: true,
            attempt: true,
            maxAttempts: true,
            createdAt: true,
            completedAt: true,
            error: true,
          },
        },
      },
    })

    if (!order) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    return NextResponse.json(order)
  } catch (error) {
    console.error('Error getting order:', error)
    return NextResponse.json(
      { error: 'Failed to get order' },
      { status: 500 }
    )
  }
}

/**
 * PATCH /api/v1/admin/orders/[id]
 * Update order (status, server credentials, etc.)
 */
export async function PATCH(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const session = await auth()

    if (!session || session.user.userType !== 'staff') {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { id: orderId } = await params
    const body = await request.json()

    // Find existing order
    const existingOrder = await prisma.order.findUnique({
      where: { id: orderId },
    })

    if (!existingOrder) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    // Build update data
    const updateData: {
      status?: OrderStatus
      serverIp?: string
      serverPasswordEncrypted?: string
      sshPort?: number
      serverReadyAt?: Date
      failureReason?: string
      tools?: string[]
      domain?: string
      customer?: string
      companyName?: string
      licenseKey?: string
      netcupServerId?: string
    } = {}

    // Handle status update
    if (body.status) {
      updateData.status = body.status as OrderStatus
    }

    // Handle server credentials
    if (body.serverIp) {
      updateData.serverIp = body.serverIp

      // Try to auto-link to Netcup server by IP
      if (!existingOrder.netcupServerId) {
        try {
          const netcupServer = await netcupService.findServerByIp(body.serverIp)
          if (netcupServer) {
            updateData.netcupServerId = netcupServer.id
            console.log(`Auto-linked order ${orderId} to Netcup server ${netcupServer.id} (${netcupServer.name})`)
          }
        } catch (error) {
          // Not critical - just log and continue
          console.log('Could not auto-link Netcup server:', error instanceof Error ? error.message : 'Not authenticated')
        }
      }
    }

    // Handle explicit netcupServerId (manual linking)
    if (body.netcupServerId) {
      updateData.netcupServerId = body.netcupServerId
    }

    if (body.serverPassword) {
      // Encrypt the password before storing
      updateData.serverPasswordEncrypted = credentialService.encrypt(body.serverPassword)
    }

    if (body.sshPort) {
      updateData.sshPort = body.sshPort
    }

    // Handle tools update (only before provisioning starts)
    if (body.tools && Array.isArray(body.tools)) {
      // Only allow tools update before provisioning
      const provisioningStatuses: OrderStatus[] = [
        OrderStatus.PROVISIONING,
        OrderStatus.FULFILLED,
        OrderStatus.EMAIL_CONFIGURED,
      ]
      if (provisioningStatuses.includes(existingOrder.status)) {
        return NextResponse.json(
          { error: 'Cannot modify tools after provisioning has started' },
          { status: 400 }
        )
      }
      updateData.tools = body.tools
    }

    // Handle domain update (only before provisioning starts)
    if (body.domain) {
      const provisioningStatuses: OrderStatus[] = [
        OrderStatus.PROVISIONING,
        OrderStatus.FULFILLED,
        OrderStatus.EMAIL_CONFIGURED,
      ]
      if (provisioningStatuses.includes(existingOrder.status)) {
        return NextResponse.json(
          { error: 'Cannot modify domain after provisioning has started' },
          { status: 400 }
        )
      }
      updateData.domain = body.domain
    }

    // Handle provisioning config fields (only before provisioning starts)
    if (body.customer !== undefined || body.companyName !== undefined || body.licenseKey !== undefined) {
      const provisioningStatuses: OrderStatus[] = [
        OrderStatus.PROVISIONING,
        OrderStatus.FULFILLED,
        OrderStatus.EMAIL_CONFIGURED,
      ]
      if (provisioningStatuses.includes(existingOrder.status)) {
        return NextResponse.json(
          { error: 'Cannot modify provisioning config after provisioning has started' },
          { status: 400 }
        )
      }
      if (body.customer) {
        updateData.customer = body.customer
      }
      if (body.companyName) {
        updateData.companyName = body.companyName
      }
      if (body.licenseKey) {
        updateData.licenseKey = body.licenseKey
      }
    }

    // Track if we should trigger DNS verification after update
    let shouldTriggerDnsVerification = false

    // Auto-transition when credentials are saved:
    // AWAITING_SERVER → DNS_PENDING (skip SERVER_READY, go straight to DNS verification)
    // This happens regardless of automation mode
    if (
      (body.serverIp || body.serverPassword) &&
      existingOrder.status === OrderStatus.AWAITING_SERVER &&
      !body.status // Only auto-transition if no explicit status is provided
    ) {
      updateData.status = OrderStatus.DNS_PENDING
      updateData.serverReadyAt = new Date()
      shouldTriggerDnsVerification = true

      // Auto-populate provisioning config if not already set
      // This ensures provisioning can proceed without manual config step
      if (!existingOrder.customer && !updateData.customer) {
        // Generate customer identifier from domain (e.g., "example.com" → "example")
        const domain = existingOrder.domain || ''
        updateData.customer = domain.split('.')[0].toLowerCase().replace(/[^a-z0-9]/g, '') || 'customer'
      }
      if (!existingOrder.companyName && !updateData.companyName) {
        // Use user's company or name, or derive from domain
        const user = await prisma.user.findUnique({ where: { id: existingOrder.userId } })
        updateData.companyName = user?.company || user?.name || existingOrder.domain || 'Company'
      }
      if (!existingOrder.licenseKey && !updateData.licenseKey) {
        // Generate a unique license key
        updateData.licenseKey = `LB-${crypto.randomBytes(8).toString('hex').toUpperCase()}`
      }
    }

    // Also trigger DNS verification when explicitly setting status to DNS_PENDING
    if (body.status === OrderStatus.DNS_PENDING) {
      shouldTriggerDnsVerification = true
    }

    // Set serverReadyAt when explicitly setting status to SERVER_READY or DNS_PENDING
    if (
      (body.status === OrderStatus.SERVER_READY || body.status === OrderStatus.DNS_PENDING) &&
      !existingOrder.serverReadyAt
    ) {
      updateData.serverReadyAt = new Date()
    }

    // Update order
    const order = await prisma.order.update({
      where: { id: orderId },
      data: updateData,
      include: {
        user: {
          select: {
            id: true,
            name: true,
            email: true,
            company: true,
          },
        },
      },
    })

    // Trigger DNS verification if credentials were saved or status changed to DNS_PENDING
    // This runs regardless of automation mode - always verify DNS when credentials are ready
    if (shouldTriggerDnsVerification && order.serverIp) {
      try {
        console.log(`Triggering DNS verification for order ${orderId}`)
        const dnsResult = await runDnsVerification(orderId)
        console.log(
          `DNS verification for order ${orderId}: ${dnsResult.allPassed ? 'PASSED' : 'PENDING'} ` +
            `(${dnsResult.passedCount}/${dnsResult.totalSubdomains} subdomains)`
        )
        // Note: runDnsVerification automatically transitions to DNS_READY if all checks pass
      } catch (error) {
        // Log but don't fail the request - DNS verification can be retried
        console.error('DNS verification failed:', error)
      }
    }

    // Trigger automation processing if credentials were saved or status changed
    // This will check if the order is in AUTO mode and process the next step
    if (body.serverIp || body.serverPassword || body.status) {
      try {
        const result = await processAutomation(orderId)
        if (result.triggered) {
          console.log(`Automation triggered for order ${orderId}: ${result.action}`)
        }
      } catch (error) {
        // Log but don't fail the request - automation is async
        console.error('Automation processing failed:', error)
      }
    }

    return NextResponse.json(order)
  } catch (error) {
    console.error('Error updating order:', error)
    return NextResponse.json(
      { error: 'Failed to update order' },
      { status: 500 }
    )
  }
}

/**
 * DELETE /api/v1/admin/orders/[id]
 * Delete an order and all related records (logs, jobs, DNS verification)
 * Does NOT touch the actual server - just removes from Hub database
 */
export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    // Require orders:delete permission (OWNER, ADMIN only)
    await requireStaffPermission('orders:delete')

    const { id: orderId } = await params

    // Find existing order
    const existingOrder = await prisma.order.findUnique({
      where: { id: orderId },
      include: {
        dnsVerification: true,
      },
    })

    if (!existingOrder) {
      return NextResponse.json({ error: 'Order not found' }, { status: 404 })
    }

    // Delete in correct order to respect foreign key constraints
    // 1. Delete DNS records (if DNS verification exists)
    if (existingOrder.dnsVerification) {
      await prisma.dnsRecord.deleteMany({
        where: { dnsVerificationId: existingOrder.dnsVerification.id },
      })
      await prisma.dnsVerification.delete({
        where: { id: existingOrder.dnsVerification.id },
      })
    }

    // 2. Delete provisioning logs
    await prisma.provisioningLog.deleteMany({
      where: { orderId },
    })

    // 3. Delete jobs
    await prisma.provisioningJob.deleteMany({
      where: { orderId },
    })

    // 4. Delete the order itself
    await prisma.order.delete({
      where: { id: orderId },
    })

    return NextResponse.json({
      success: true,
      message: `Order ${orderId} and all related records deleted`,
    })
  } catch (error: any) {
    if (error?.status) {
      return NextResponse.json({ error: error.message }, { status: error.status })
    }
    console.error('Error deleting order:', error)
    return NextResponse.json(
      { error: 'Failed to delete order' },
      { status: 500 }
    )
  }
}

