import { Context } from '../types/context'

export interface ResourceInventoryFilter {
  provider?: string
  resourceType?: string
  region?: string
  siteId?: string
  tags?: string[]
}

export interface ResourceInventoryItem {
  id: string
  resourceType: string
  provider: string
  providerId: string
  providerResourceId?: string
  name: string
  region?: string
  siteId?: string
  metadata: Record<string, any>
  tags: string[]
  discoveredAt: Date
  lastSyncedAt: Date
  createdAt: Date
  updatedAt: Date
}

export interface CreateResourceInventoryInput {
  resourceType: string
  provider: string
  providerId: string
  providerResourceId?: string
  name: string
  region?: string
  siteId?: string
  metadata?: Record<string, any>
  tags?: string[]
}

export interface UpdateResourceInventoryInput {
  name?: string
  region?: string
  siteId?: string
  metadata?: Record<string, any>
  tags?: string[]
}

export async function getResourceInventory(
  context: Context,
  filter?: ResourceInventoryFilter
): Promise<ResourceInventoryItem[]> {
  const db = context.db
  let query = 'SELECT * FROM resource_inventory WHERE 1=1'
  const params: unknown[] = []
  let paramCount = 1

  // Tenant-aware filtering (superior to Azure)
  if (context.tenantContext) {
    if (context.tenantContext.isSystemAdmin) {
      // System admins can see all resources
    } else if (context.tenantContext.tenantId) {
      // Filter by tenant
      query += ` AND (tenant_id = $${paramCount} OR tenant_id IS NULL)`
      params.push(context.tenantContext.tenantId)
      paramCount++
    } else {
      // Non-tenant users only see system resources
      query += ` AND tenant_id IS NULL`
    }
  } else {
    // Unauthenticated users see nothing
    query += ` AND 1=0`
  }

  if (filter?.provider) {
    query += ` AND provider = $${paramCount}`
    params.push(filter.provider)
    paramCount++
  }

  if (filter?.resourceType) {
    query += ` AND resource_type = $${paramCount}`
    params.push(filter.resourceType)
    paramCount++
  }

  if (filter?.region) {
    query += ` AND region = $${paramCount}`
    params.push(filter.region)
    paramCount++
  }

  if (filter?.siteId) {
    query += ` AND site_id = $${paramCount}`
    params.push(filter.siteId)
    paramCount++
  }

  if (filter?.tags && filter.tags.length > 0) {
    query += ` AND tags @> $${paramCount}::jsonb`
    params.push(JSON.stringify(filter.tags))
    paramCount++
  }

  query += ' ORDER BY discovered_at DESC'

  const result = await db.query(query, params)
  return result.rows.map(mapResourceInventoryItem)
}

export async function getResourceInventoryItem(
  context: Context,
  id: string
): Promise<ResourceInventoryItem> {
  const db = context.db
  let query = 'SELECT * FROM resource_inventory WHERE id = $1'
  const params: unknown[] = [id]
  let paramCount = 2

  // Tenant-aware filtering
  if (context.tenantContext) {
    if (context.tenantContext.isSystemAdmin) {
      // System admins can see all resources
    } else if (context.tenantContext.tenantId) {
      query += ` AND (tenant_id = $${paramCount} OR tenant_id IS NULL)`
      params.push(context.tenantContext.tenantId)
      paramCount++
    } else {
      query += ` AND tenant_id IS NULL`
    }
  } else {
    query += ` AND 1=0`
  }

  const result = await db.query(query, params)

  if (result.rows.length === 0) {
    throw new Error('Resource inventory item not found')
  }

  return mapResourceInventoryItem(result.rows[0])
}

export async function getResourceInventoryByProvider(
  context: Context,
  provider: string,
  providerId: string
): Promise<ResourceInventoryItem | null> {
  const db = context.db
  const result = await db.query(
    'SELECT * FROM resource_inventory WHERE provider = $1 AND provider_id = $2',
    [provider, providerId]
  )

  if (result.rows.length === 0) {
    return null
  }

  return mapResourceInventoryItem(result.rows[0])
}

export async function createResourceInventoryItem(
  context: Context,
  input: CreateResourceInventoryInput
): Promise<ResourceInventoryItem> {
  const db = context.db
  
  // Set tenant_id from context if available
  const tenantId = context.tenantContext?.tenantId || null
  
  const result = await db.query(
    `INSERT INTO resource_inventory (
      resource_type, provider, provider_id, provider_resource_id, name, 
      region, site_id, tenant_id, metadata, tags
    ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
    RETURNING *`,
    [
      input.resourceType,
      input.provider,
      input.providerId,
      input.providerResourceId || null,
      input.name,
      input.region || null,
      input.siteId || null,
      JSON.stringify(input.metadata || {}),
      JSON.stringify(input.tags || []),
    ]
  )

  return mapResourceInventoryItem(result.rows[0])
}

export async function updateResourceInventoryItem(
  context: Context,
  id: string,
  input: UpdateResourceInventoryInput
): Promise<ResourceInventoryItem> {
  const db = context.db
  const updates: string[] = []
  const params: unknown[] = []
  let paramCount = 1

  if (input.name !== undefined) {
    updates.push(`name = $${paramCount}`)
    params.push(input.name)
    paramCount++
  }

  if (input.region !== undefined) {
    updates.push(`region = $${paramCount}`)
    params.push(input.region)
    paramCount++
  }

  if (input.siteId !== undefined) {
    updates.push(`site_id = $${paramCount}`)
    params.push(input.siteId)
    paramCount++
  }

  if (input.metadata !== undefined) {
    updates.push(`metadata = $${paramCount}::jsonb`)
    params.push(JSON.stringify(input.metadata))
    paramCount++
  }

  if (input.tags !== undefined) {
    updates.push(`tags = $${paramCount}::jsonb`)
    params.push(JSON.stringify(input.tags))
    paramCount++
  }

  // Always update last_synced_at
  updates.push(`last_synced_at = NOW()`)

  if (updates.length === 0) {
    return getResourceInventoryItem(context, id)
  }

  params.push(id)
  const result = await db.query(
    `UPDATE resource_inventory SET ${updates.join(', ')} WHERE id = $${paramCount} RETURNING *`,
    params
  )

  return mapResourceInventoryItem(result.rows[0])
}

export async function upsertResourceInventoryItem(
  context: Context,
  input: CreateResourceInventoryInput
): Promise<ResourceInventoryItem> {
  const db = context.db
  const existing = await getResourceInventoryByProvider(context, input.provider, input.providerId)

  if (existing) {
    return updateResourceInventoryItem(context, existing.id, {
      name: input.name,
      region: input.region,
      siteId: input.siteId,
      metadata: input.metadata,
      tags: input.tags,
    })
  }

  return createResourceInventoryItem(context, input)
}

export async function deleteResourceInventoryItem(
  context: Context,
  id: string
): Promise<boolean> {
  const db = context.db
  await db.query('DELETE FROM resource_inventory WHERE id = $1', [id])
  return true
}

export async function syncResourceInventory(
  context: Context,
  provider: string,
  resources: CreateResourceInventoryInput[]
): Promise<number> {
  let synced = 0
  for (const resource of resources) {
    await upsertResourceInventoryItem(context, { ...resource, provider })
    synced++
  }
  return synced
}

interface ResourceInventoryRow {
  id: string
  resource_type: string
  provider: string
  provider_id: string
  provider_resource_id: string | null
  name: string
  region: string | null
  site_id: string | null
  tenant_id: string | null
  metadata: string | Record<string, unknown> | null
  tags: string[] | null
  discovered_at: Date
  last_synced_at: Date | null
  created_at: Date
  updated_at: Date
  [key: string]: unknown
}

function mapResourceInventoryItem(row: ResourceInventoryRow): ResourceInventoryItem {
  const metadata = typeof row.metadata === 'string' 
    ? (JSON.parse(row.metadata) as Record<string, unknown>)
    : ((row.metadata as Record<string, unknown>) || {})

  return {
    id: row.id,
    resourceType: row.resource_type,
    provider: row.provider,
    providerId: row.provider_id,
    providerResourceId: row.provider_resource_id || null,
    name: row.name,
    region: row.region || null,
    siteId: row.site_id || null,
    metadata,
    tags: row.tags || [],
    discoveredAt: row.discovered_at,
    lastSyncedAt: row.last_synced_at || null,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

