import * as fs from 'fs'
import * as path from 'path'
import type { SteamGame } from '../../shared/types'

// Common Steam installation paths on Windows
const STEAM_PATHS = [
  'C:\\Program Files (x86)\\Steam',
  'C:\\Program Files\\Steam',
  'D:\\Steam',
  'D:\\SteamLibrary',
  'E:\\Steam',
  'E:\\SteamLibrary',
]

let cachedSteamPath: string | null = null

export function getSteamPath(): string | null {
  if (cachedSteamPath) {
    return cachedSteamPath
  }

  // Try common paths
  for (const steamPath of STEAM_PATHS) {
    if (fs.existsSync(path.join(steamPath, 'steam.exe')) ||
        fs.existsSync(path.join(steamPath, 'steamapps'))) {
      cachedSteamPath = steamPath
      return steamPath
    }
  }

  // Try to find via registry (would require node-winreg or similar)
  // For now, just check common paths

  return null
}

export async function getSteamGames(): Promise<SteamGame[]> {
  const steamPath = getSteamPath()
  if (!steamPath) {
    console.log('Steam not found')
    return []
  }

  const games: SteamGame[] = []
  const libraryPaths = await getLibraryPaths(steamPath)

  for (const libraryPath of libraryPaths) {
    const steamAppsPath = path.join(libraryPath, 'steamapps')
    if (!fs.existsSync(steamAppsPath)) continue

    try {
      const files = fs.readdirSync(steamAppsPath)
      const manifests = files.filter((f) => f.startsWith('appmanifest_') && f.endsWith('.acf'))

      for (const manifest of manifests) {
        const game = await parseAppManifest(path.join(steamAppsPath, manifest), libraryPath)
        if (game) {
          games.push(game)
        }
      }
    } catch (error) {
      console.error(`Error reading steam apps from ${steamAppsPath}:`, error)
    }
  }

  return games.sort((a, b) => a.name.localeCompare(b.name))
}

async function getLibraryPaths(steamPath: string): Promise<string[]> {
  const paths: string[] = [steamPath]
  const libraryFoldersPath = path.join(steamPath, 'steamapps', 'libraryfolders.vdf')

  if (!fs.existsSync(libraryFoldersPath)) {
    return paths
  }

  try {
    const content = fs.readFileSync(libraryFoldersPath, 'utf8')
    const libraryPaths = parseLibraryFolders(content)
    paths.push(...libraryPaths.filter((p) => !paths.includes(p)))
  } catch (error) {
    console.error('Error reading library folders:', error)
  }

  return paths
}

function parseLibraryFolders(content: string): string[] {
  const paths: string[] = []

  // Simple VDF parser for library folders
  // Format: "path" "C:\\SteamLibrary"
  const pathRegex = /"path"\s+"([^"]+)"/g
  let match

  while ((match = pathRegex.exec(content)) !== null) {
    const libPath = match[1].replace(/\\\\/g, '\\')
    if (fs.existsSync(libPath)) {
      paths.push(libPath)
    }
  }

  return paths
}

async function parseAppManifest(manifestPath: string, libraryPath: string): Promise<SteamGame | null> {
  try {
    const content = fs.readFileSync(manifestPath, 'utf8')

    const appIdMatch = content.match(/"appid"\s+"(\d+)"/)
    const nameMatch = content.match(/"name"\s+"([^"]+)"/)
    const installDirMatch = content.match(/"installdir"\s+"([^"]+)"/)

    if (!appIdMatch || !nameMatch || !installDirMatch) {
      return null
    }

    const appId = appIdMatch[1]
    const name = nameMatch[1]
    const installDir = installDirMatch[1]

    // Filter out tools, servers, etc.
    const skipTypes = ['Tool', 'Config', 'DLC', 'Music', 'Video']
    const typeMatch = content.match(/"type"\s+"([^"]+)"/)
    if (typeMatch && skipTypes.includes(typeMatch[1])) {
      return null
    }

    const fullInstallPath = path.join(libraryPath, 'steamapps', 'common', installDir)
    let executable: string | undefined

    // Try to find main executable
    if (fs.existsSync(fullInstallPath)) {
      executable = findMainExecutable(fullInstallPath, name)
    }

    return {
      appId,
      name,
      installDir: fullInstallPath,
      executable,
      iconPath: getGameIconPath(steamPath, appId),
    }
  } catch (error) {
    console.error(`Error parsing manifest ${manifestPath}:`, error)
    return null
  }
}

function findMainExecutable(installPath: string, gameName: string): string | undefined {
  try {
    const files = fs.readdirSync(installPath)
    const exeFiles = files.filter((f) => f.endsWith('.exe'))

    if (exeFiles.length === 0) {
      // Check subdirectories (one level deep)
      for (const dir of files) {
        const subPath = path.join(installPath, dir)
        if (fs.statSync(subPath).isDirectory()) {
          const subFiles = fs.readdirSync(subPath)
          const subExe = subFiles.filter((f) => f.endsWith('.exe'))
          exeFiles.push(...subExe.map((f) => path.join(dir, f)))
        }
      }
    }

    if (exeFiles.length === 0) return undefined

    // Try to find exe that matches game name
    const lowerName = gameName.toLowerCase().replace(/[^a-z0-9]/g, '')
    for (const exe of exeFiles) {
      const lowerExe = exe.toLowerCase().replace(/[^a-z0-9]/g, '')
      if (lowerExe.includes(lowerName) || lowerName.includes(lowerExe.replace('.exe', ''))) {
        return exe
      }
    }

    // Filter out common non-game executables
    const skipExes = [
      'unins', 'setup', 'install', 'config', 'crash', 'report',
      'launcher', 'updater', 'redistributable', 'vcredist', 'directx',
      'dxsetup', 'ue4prereqsetup', 'dotnet',
    ]

    const gameExes = exeFiles.filter((exe) => {
      const lower = exe.toLowerCase()
      return !skipExes.some((skip) => lower.includes(skip))
    })

    return gameExes[0] || exeFiles[0]
  } catch {
    return undefined
  }
}

function getGameIconPath(steamPath: string | null, appId: string): string | undefined {
  if (!steamPath) return undefined

  // Steam stores icons in appcache/librarycache
  const iconPath = path.join(steamPath, 'appcache', 'librarycache', `${appId}_icon.jpg`)
  if (fs.existsSync(iconPath)) {
    return iconPath
  }

  // Try header image
  const headerPath = path.join(steamPath, 'appcache', 'librarycache', `${appId}_header.jpg`)
  if (fs.existsSync(headerPath)) {
    return headerPath
  }

  return undefined
}

// Re-export for use
const steamPath = getSteamPath()
