import { Order, SubscriptionTier } from '@prisma/client'
import crypto from 'crypto'
import { credentialService } from '@/lib/services/credential-service'

/**
 * Configuration format expected by the Docker container's entrypoint.sh
 */
export interface JobConfig {
  server: {
    ip: string
    port: number
    rootPassword: string
  }
  customer: string
  domain: string
  companyName: string
  licenseKey: string
  dashboardTier: string
  tools: string[]
  // Hub communication settings
  hubUrl: string
  hubTelemetryEnabled: boolean
  // Docker Hub credentials (optional - for private images or rate limit bypass)
  dockerHub?: {
    username: string
    token: string
    registry?: string // Custom registry URL, defaults to Docker Hub
  }
  // Gitea registry credentials (optional - for private LetsBe images)
  gitea?: {
    registry: string
    username: string
    token: string
  }
}

/**
 * Order with decrypted password for config generation
 */
export interface OrderWithPassword extends Omit<Order, 'serverPasswordEncrypted'> {
  serverPassword: string
}

/**
 * Decrypt the server password stored in the database
 * Supports both new (CREDENTIAL_ENCRYPTION_KEY) and legacy (ENCRYPTION_KEY) formats
 */
export function decryptPassword(encrypted: string): string {
  try {
    return credentialService.decrypt(encrypted)
  } catch {
    // Fall back to legacy format for migration
    return credentialService.decryptLegacy(encrypted)
  }
}

/**
 * Map subscription tier to dashboard tier string expected by setup scripts
 */
function mapTierToDashboardTier(tier: SubscriptionTier): string {
  switch (tier) {
    case SubscriptionTier.HUB_DASHBOARD:
      return 'HUB_DASHBOARD'
    case SubscriptionTier.ADVANCED:
      return 'ADVANCED'
    default:
      return 'ADVANCED'
  }
}

/**
 * Docker Hub credentials for the job config
 */
export interface DockerHubCredentials {
  username: string
  token: string
  registry?: string
}

/**
 * Gitea registry credentials for the job config
 */
export interface GiteaCredentials {
  registry: string
  username: string
  token: string
}

/**
 * Generate the job configuration from an order
 * This config is mounted into the Docker container at /job/config.json
 */
export function generateJobConfig(
  order: Order,
  decryptedPassword: string,
  dockerHub?: DockerHubCredentials,
  gitea?: GiteaCredentials
): JobConfig {
  if (!order.serverIp) {
    throw new Error('Order is missing server IP')
  }
  if (!order.customer) {
    throw new Error('Order is missing customer identifier')
  }
  if (!order.companyName) {
    throw new Error('Order is missing company name')
  }
  if (!order.licenseKey) {
    throw new Error('Order is missing license key')
  }

  const config: JobConfig = {
    server: {
      ip: order.serverIp,
      port: order.sshPort || 22,
      rootPassword: decryptedPassword,
    },
    customer: order.customer,
    domain: order.domain,
    companyName: order.companyName,
    licenseKey: order.licenseKey,
    dashboardTier: mapTierToDashboardTier(order.tier),
    tools: order.tools,
    hubUrl: process.env.HUB_URL || process.env.NEXTAUTH_URL || 'http://localhost:3000',
    hubTelemetryEnabled: true,
  }

  // Add Docker Hub credentials if provided
  if (dockerHub?.username && dockerHub?.token) {
    config.dockerHub = {
      username: dockerHub.username,
      token: dockerHub.token,
      registry: dockerHub.registry,
    }
  }

  // Add Gitea registry credentials if provided
  if (gitea?.username && gitea?.token && gitea?.registry) {
    config.gitea = {
      registry: gitea.registry,
      username: gitea.username,
      token: gitea.token,
    }
  }

  return config
}

/**
 * Generate a secure runner token for container authentication
 * This token is used by the container to authenticate API calls back to the Hub
 */
export function generateRunnerToken(): string {
  return crypto.randomBytes(32).toString('hex')
}

/**
 * Hash a runner token for storage in the database
 */
export function hashRunnerToken(token: string): string {
  return crypto.createHash('sha256').update(token).digest('hex')
}

/**
 * Verify a runner token against its hash
 */
export function verifyRunnerToken(token: string, hash: string): boolean {
  const tokenHash = hashRunnerToken(token)
  return crypto.timingSafeEqual(Buffer.from(tokenHash), Buffer.from(hash))
}
