import { getDb } from '../db'
import { Context } from '../types/context'
import { AppErrors } from '../lib/errors'

export interface TestEnvironment {
  id: string
  name: string
  userId: string
  tenantId?: string
  region: string
  status: 'RUNNING' | 'STOPPED' | 'PROVISIONING' | 'ERROR' | 'DELETING'
  resources: {
    vms: number
    storage: string
    network: string
  }
  expiresAt?: Date
  createdAt: Date
  updatedAt: Date
}

export interface CreateTestEnvironmentInput {
  name: string
  region: string
  resources?: {
    vms?: number
    storage?: string
    network?: string
  }
  expiresAt?: Date
}

export interface UpdateTestEnvironmentInput {
  name?: string
  region?: string
  resources?: {
    vms?: number
    storage?: string
    network?: string
  }
  expiresAt?: Date
}

/**
 * Create a new test environment
 */
export async function createTestEnvironment(
  context: Context,
  input: CreateTestEnvironmentInput
): Promise<TestEnvironment> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const tenantId = context.tenantContext?.tenantId || null

  // Default resources
  const resources = {
    vms: input.resources?.vms || 1,
    storage: input.resources?.storage || '20 GB',
    network: input.resources?.network || '10.0.0.0/16',
  }

  const result = await db.query(
    `INSERT INTO test_environments (name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
     RETURNING id, name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at`,
    [
      input.name,
      context.user.id,
      tenantId,
      input.region,
      'PROVISIONING',
      JSON.stringify(resources),
      input.expiresAt || null,
    ]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    userId: row.user_id,
    tenantId: row.tenant_id,
    region: row.region,
    status: row.status,
    resources: JSON.parse(row.resources),
    expiresAt: row.expires_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

/**
 * Get all test environments for the current user
 */
export async function getTestEnvironments(context: Context): Promise<TestEnvironment[]> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const result = await db.query(
    `SELECT id, name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at
     FROM test_environments
     WHERE user_id = $1 AND status != 'DELETING'
     ORDER BY created_at DESC`,
    [context.user.id]
  )

  return result.rows.map((row) => ({
    id: row.id,
    name: row.name,
    userId: row.user_id,
    tenantId: row.tenant_id,
    region: row.region,
    status: row.status,
    resources: JSON.parse(row.resources),
    expiresAt: row.expires_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }))
}

/**
 * Get a single test environment by ID
 */
export async function getTestEnvironment(
  context: Context,
  id: string
): Promise<TestEnvironment> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const result = await db.query(
    `SELECT id, name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at
     FROM test_environments
     WHERE id = $1 AND user_id = $2`,
    [id, context.user.id]
  )

  if (result.rows.length === 0) {
    throw AppErrors.notFound('Test environment not found')
  }

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    userId: row.user_id,
    tenantId: row.tenant_id,
    region: row.region,
    status: row.status,
    resources: JSON.parse(row.resources),
    expiresAt: row.expires_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

/**
 * Start a test environment
 */
export async function startTestEnvironment(
  context: Context,
  id: string
): Promise<TestEnvironment> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const result = await db.query(
    `UPDATE test_environments
     SET status = 'PROVISIONING', updated_at = NOW()
     WHERE id = $1 AND user_id = $2 AND status = 'STOPPED'
     RETURNING id, name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at`,
    [id, context.user.id]
  )

  if (result.rows.length === 0) {
    throw AppErrors.notFound('Test environment not found or cannot be started')
  }

  // Simulate provisioning - in real implementation, would trigger actual provisioning
  setTimeout(async () => {
    await db.query(
      `UPDATE test_environments SET status = 'RUNNING', updated_at = NOW() WHERE id = $1`,
      [id]
    )
  }, 2000)

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    userId: row.user_id,
    tenantId: row.tenant_id,
    region: row.region,
    status: 'PROVISIONING',
    resources: JSON.parse(row.resources),
    expiresAt: row.expires_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

/**
 * Stop a test environment
 */
export async function stopTestEnvironment(
  context: Context,
  id: string
): Promise<TestEnvironment> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const result = await db.query(
    `UPDATE test_environments
     SET status = 'STOPPED', updated_at = NOW()
     WHERE id = $1 AND user_id = $2 AND status = 'RUNNING'
     RETURNING id, name, user_id, tenant_id, region, status, resources, expires_at, created_at, updated_at`,
    [id, context.user.id]
  )

  if (result.rows.length === 0) {
    throw AppErrors.notFound('Test environment not found or cannot be stopped')
  }

  const row = result.rows[0]
  return {
    id: row.id,
    name: row.name,
    userId: row.user_id,
    tenantId: row.tenant_id,
    region: row.region,
    status: 'STOPPED',
    resources: JSON.parse(row.resources),
    expiresAt: row.expires_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

/**
 * Delete a test environment
 */
export async function deleteTestEnvironment(context: Context, id: string): Promise<boolean> {
  if (!context.user) {
    throw AppErrors.unauthenticated('Authentication required')
  }

  const db = getDb()
  const result = await db.query(
    `UPDATE test_environments
     SET status = 'DELETING', updated_at = NOW()
     WHERE id = $1 AND user_id = $2
     RETURNING id`,
    [id, context.user.id]
  )

  if (result.rows.length === 0) {
    throw AppErrors.notFound('Test environment not found')
  }

  // In real implementation, would trigger actual deletion
  // For now, just mark as deleting
  return true
}

