import { queryGameDb, getGameDbConfig, getGameDbPool } from '@/lib/game-db'
import { prisma } from '@/lib/db'
import type { RowDataPacket } from 'mysql2'

// ==========================================
// TYPES
// ==========================================

export interface InventoryItem {
  name: string
  label: string
  count: number
  weight?: number
  slot?: number
  description?: string
  image?: string
  imageUrl?: string
  metadata?: Record<string, any>
  unique?: boolean
  useable?: boolean
}

export interface InventoryData {
  items: InventoryItem[]
  maxWeight?: number
  currentWeight?: number
  maxSlots?: number
}

// ==========================================
// INVENTORY IMAGE SETTINGS
// ==========================================

interface InventoryImageSettings {
  basePath: string
  format: string
  fallbackImage: string
}

/**
 * Get all inventory image settings
 */
export async function getInventoryImageSettings(): Promise<InventoryImageSettings> {
  try {
    const settings = await prisma.systemSetting.findMany({
      where: {
        key: {
          in: ['inventoryImagePath', 'inventoryImageFormat', 'inventoryFallbackImage']
        }
      }
    })
    
    const settingsMap = Object.fromEntries(settings.map(s => [s.key, s.value]))
    
    return {
      basePath: settingsMap.inventoryImagePath || '/images/items/',
      format: settingsMap.inventoryImageFormat || 'png',
      fallbackImage: settingsMap.inventoryFallbackImage || '/images/items/default.png',
    }
  } catch {
    return {
      basePath: '/images/items/',
      format: 'png',
      fallbackImage: '/images/items/default.png',
    }
  }
}

/**
 * Get the configured inventory image base path
 */
export async function getInventoryImageBasePath(): Promise<string> {
  const settings = await getInventoryImageSettings()
  return settings.basePath
}

/**
 * Build the full URL for an inventory item image
 */
export async function getItemImageUrl(itemName: string): Promise<string> {
  const settings = await getInventoryImageSettings()
  
  // Clean item name for filename
  const cleanName = itemName.toLowerCase().replace(/[^a-z0-9_-]/g, '')
  
  // Build URL with configured format
  return `${settings.basePath}${cleanName}.${settings.format}`
}

// ==========================================
// FRAMEWORK DETECTION
// ==========================================

type Framework = 'ESX' | 'QBCORE'

async function getFramework(): Promise<Framework> {
  const config = await getGameDbConfig()
  return config?.framework || 'ESX'
}

// ==========================================
// INVENTORY QUERIES
// ==========================================

/**
 * Get inventory for a character
 */
export async function getCharacterInventory(characterId: string): Promise<InventoryData> {
  const framework = await getFramework()
  
  try {
    if (framework === 'QBCORE') {
      return await getQBCoreInventory(characterId)
    } else {
      return await getESXInventory(characterId)
    }
  } catch (error) {
    console.error('[InventoryService] Error getting inventory:', error)
    return { items: [] }
  }
}

// ==========================================
// ESX INVENTORY
// ==========================================

async function getESXInventory(identifier: string): Promise<InventoryData> {
  try {
    // ESX stores inventory as JSON in users table
    const rows = await queryGameDb<RowDataPacket[]>(
      `SELECT inventory, loadout FROM users WHERE identifier = ?`,
      [identifier]
    )
    
    if (!rows || rows.length === 0) {
      return { items: [] }
    }
    
    const row = rows[0]
    const inventoryData = parseJson(row.inventory)
    const loadoutData = parseJson(row.loadout)
    
    const items: InventoryItem[] = []
    const basePath = await getInventoryImageBasePath()
    
    // Parse ESX inventory format (can be array or object)
    if (Array.isArray(inventoryData)) {
      for (const item of inventoryData) {
        if (item && item.count > 0) {
          items.push({
            name: item.name,
            label: item.label || item.name,
            count: item.count || 1,
            slot: item.slot,
            metadata: item.metadata,
            image: item.name,
            imageUrl: `${basePath}${item.name.toLowerCase()}.png`,
          })
        }
      }
    } else if (inventoryData && typeof inventoryData === 'object') {
      for (const [key, item] of Object.entries(inventoryData)) {
        const itemData = item as any
        if (itemData && (itemData.count > 0 || itemData.amount > 0)) {
          items.push({
            name: itemData.name || key,
            label: itemData.label || itemData.name || key,
            count: itemData.count || itemData.amount || 1,
            slot: itemData.slot,
            metadata: itemData.metadata,
            image: itemData.name || key,
            imageUrl: `${basePath}${(itemData.name || key).toLowerCase()}.png`,
          })
        }
      }
    }
    
    // Parse loadout (weapons)
    if (Array.isArray(loadoutData)) {
      for (const weapon of loadoutData) {
        if (weapon && weapon.name) {
          items.push({
            name: weapon.name,
            label: weapon.label || weapon.name,
            count: 1,
            metadata: { ammo: weapon.ammo, components: weapon.components },
            image: weapon.name,
            imageUrl: `${basePath}${weapon.name.toLowerCase()}.png`,
          })
        }
      }
    }
    
    return { items }
  } catch (error) {
    console.error('[ESX] Error getting inventory:', error)
    return { items: [] }
  }
}

// ==========================================
// QBCORE INVENTORY
// ==========================================

async function getQBCoreInventory(citizenid: string): Promise<InventoryData> {
  try {
    // QBCore stores inventory as JSON in players table
    const rows = await queryGameDb<RowDataPacket[]>(
      `SELECT inventory FROM players WHERE citizenid = ?`,
      [citizenid]
    )
    
    if (!rows || rows.length === 0) {
      return { items: [] }
    }
    
    const inventoryData = parseJson(rows[0].inventory)
    const items: InventoryItem[] = []
    const basePath = await getInventoryImageBasePath()
    
    // QBCore inventory format is usually an array of items with slots
    if (Array.isArray(inventoryData)) {
      for (const item of inventoryData) {
        if (item && item.name && item.amount > 0) {
          items.push({
            name: item.name,
            label: item.label || item.name,
            count: item.amount || item.count || 1,
            weight: item.weight,
            slot: item.slot,
            description: item.description,
            metadata: item.info || item.metadata,
            unique: item.unique,
            useable: item.useable,
            image: item.name,
            imageUrl: `${basePath}${item.name.toLowerCase()}.png`,
          })
        }
      }
    } else if (inventoryData && typeof inventoryData === 'object') {
      // Some servers use object format with slot keys
      for (const [slot, item] of Object.entries(inventoryData)) {
        const itemData = item as any
        if (itemData && itemData.name && (itemData.amount > 0 || itemData.count > 0)) {
          items.push({
            name: itemData.name,
            label: itemData.label || itemData.name,
            count: itemData.amount || itemData.count || 1,
            weight: itemData.weight,
            slot: parseInt(slot) || itemData.slot,
            description: itemData.description,
            metadata: itemData.info || itemData.metadata,
            unique: itemData.unique,
            useable: itemData.useable,
            image: itemData.name,
            imageUrl: `${basePath}${itemData.name.toLowerCase()}.png`,
          })
        }
      }
    }
    
    // Sort by slot
    items.sort((a, b) => (a.slot || 0) - (b.slot || 0))
    
    return { 
      items,
      maxSlots: 40, // Default QBCore inventory size
      maxWeight: 120000, // Default max weight
    }
  } catch (error) {
    console.error('[QBCore] Error getting inventory:', error)
    return { items: [] }
  }
}

// ==========================================
// VEHICLE INVENTORY
// ==========================================

export async function getVehicleInventory(plate: string): Promise<InventoryData> {
  const framework = await getFramework()
  
  try {
    if (framework === 'QBCORE') {
      // QBCore stores trunk inventory in gloveboxitems/trunkitems tables or in vehicle data
      const rows = await queryGameDb<RowDataPacket[]>(
        `SELECT items FROM trunkitems WHERE plate = ?`,
        [plate]
      )
      
      if (rows && rows.length > 0) {
        const inventoryData = parseJson(rows[0].items)
        const items: InventoryItem[] = []
        const basePath = await getInventoryImageBasePath()
        
        if (Array.isArray(inventoryData)) {
          for (const item of inventoryData) {
            if (item && item.name && item.amount > 0) {
              items.push({
                name: item.name,
                label: item.label || item.name,
                count: item.amount || 1,
                slot: item.slot,
                image: item.name,
                imageUrl: `${basePath}${item.name.toLowerCase()}.png`,
              })
            }
          }
        }
        
        return { items }
      }
    }
    
    return { items: [] }
  } catch (error) {
    console.error('[InventoryService] Error getting vehicle inventory:', error)
    return { items: [] }
  }
}

// ==========================================
// HELPERS
// ==========================================

function parseJson(value: any): any {
  if (!value) return null
  if (typeof value === 'object') return value
  try {
    return JSON.parse(value)
  } catch {
    return null
  }
}
