#!/usr/bin/env bun
import { $ } from "bun"

// Configuration
const CONFIG = {
  checkInterval: 10_000, // 10 seconds
  ap: {
    ip: "192.168.4.1",
    dhcpRange: "192.168.4.2,192.168.4.20",
    channel: 7,
  },
}

// Get AP SSID from hostname
const hostname = (await $`hostname`.text()).trim()
const AP_SSID = `${hostname}-setup`
const AP_CONNECTION_NAME = `${AP_SSID}-ap`

console.log("Starting WiFi AP Monitor...")
console.log(`AP SSID will be: ${AP_SSID}`)
console.log(`AP connection name: ${AP_CONNECTION_NAME}`)
console.log(`Checking connectivity every ${CONFIG.checkInterval / 1000} seconds\n`)

let apRunning = false

async function isConnectedToWiFi(): Promise<boolean> {
  try {
    // Check if wlan0 is connected to a WiFi network AS A CLIENT (not in AP mode)
    // We need to check if there's an active connection that is NOT our AP
    const activeConnections = await $`nmcli -t -f NAME,TYPE connection show --active`.quiet().text()
    const lines = activeConnections.trim().split("\n")

    for (const line of lines) {
      const [name, type] = line.split(":")
      // Check if there's a wifi connection that's NOT our AP
      if (type === "802-11-wireless" && name !== AP_CONNECTION_NAME) {
        return true
      }
    }

    return false
  } catch (error) {
    console.error("[isConnectedToWiFi] ERROR: Failed to check WiFi status")
    console.error(error)
    return false
  }
}

async function startAP() {
  if (apRunning) {
    console.log("[startAP] AP already running, skipping")
    return
  }

  console.log("🔴 Not connected to WiFi - Starting WiFi AP...")
  console.log(`[startAP] AP SSID: ${AP_SSID}`)
  console.log(`[startAP] AP Connection: ${AP_CONNECTION_NAME}`)

  try {
    // Check if connection profile already exists
    console.log("[startAP] Checking if connection profile exists...")
    const existsResult = await $`sudo nmcli connection show ${AP_CONNECTION_NAME}`.nothrow().quiet()

    if (existsResult.exitCode !== 0) {
      console.log("[startAP] Connection profile does not exist, creating...")

      // Create AP connection profile (open network, no password)
      await $`sudo nmcli connection add type wifi ifname wlan0 con-name ${AP_CONNECTION_NAME} autoconnect no ssid ${AP_SSID} 802-11-wireless.mode ap 802-11-wireless.band bg 802-11-wireless.channel ${CONFIG.ap.channel} ipv4.method shared ipv4.addresses ${CONFIG.ap.ip}/24`
      console.log("[startAP] ✓ Connection profile created (open network)")
    } else {
      console.log("[startAP] Connection profile already exists, reusing")
    }

    // Bring up the AP
    console.log("[startAP] Bringing up AP connection...")
    await $`sudo nmcli connection up ${AP_CONNECTION_NAME}`
    console.log("[startAP] ✓ AP connection activated")

    apRunning = true
    console.log(`✓ AP started successfully!`)
    console.log(`  SSID: ${AP_SSID}`)
    console.log(`  Password: None (open network)`)
    console.log(`  Connect and visit: http://${CONFIG.ap.ip}\n`)
  } catch (error) {
    console.error("[startAP] ERROR: Failed to start AP")
    console.error(error)
    apRunning = false
  }
}

async function stopAP() {
  if (!apRunning) {
    console.log("[stopAP] AP not running, skipping")
    return
  }

  console.log("🟢 Connected to WiFi - Stopping AP...")
  console.log(`[stopAP] Bringing down connection: ${AP_CONNECTION_NAME}`)

  try {
    // Bring down the AP connection
    await $`sudo nmcli connection down ${AP_CONNECTION_NAME}`.nothrow()
    console.log("[stopAP] ✓ AP connection deactivated")

    apRunning = false
    console.log("✓ AP stopped successfully\n")
  } catch (error) {
    console.error("[stopAP] ERROR: Failed to stop AP")
    console.error(error)
    // Set to false anyway to allow retry
    apRunning = false
  }
}

async function checkAndManageAP() {
  const connected = await isConnectedToWiFi()

  if (connected && apRunning) {
    console.log("[checkAndManageAP] WiFi connected and AP running → stopping AP")
    await stopAP()
  } else if (!connected && !apRunning) {
    console.log("[checkAndManageAP] WiFi disconnected and AP stopped → starting AP")
    await startAP()
  } else if (!connected && apRunning) {
    // AP is running but no WiFi client connection
    // Check if our saved WiFi network is available
    console.log("[checkAndManageAP] AP running, checking if saved WiFi is available...")
    const savedNetwork = await findAvailableSavedNetwork()
    if (savedNetwork) {
      console.log(
        `[checkAndManageAP] Found available saved network: ${savedNetwork}, attempting connection...`,
      )

      // Try to connect first
      const connected = await tryConnect(savedNetwork)

      if (connected) {
        console.log(`[checkAndManageAP] Successfully connected to ${savedNetwork}, stopping AP...`)
        await stopAP()
      } else {
        console.log(`[checkAndManageAP] Failed to connect to ${savedNetwork}, keeping AP running`)
        // Delete the failed connection profile
        try {
          await $`sudo nmcli connection delete ${savedNetwork}`.nothrow()
          console.log(`[checkAndManageAP] Deleted failed connection profile for ${savedNetwork}`)
        } catch (error) {
          console.error(`[checkAndManageAP] Failed to delete connection profile:`, error)
        }
      }
    }
  }
}

async function findAvailableSavedNetwork(): Promise<string | null> {
  try {
    // Get all saved WiFi connections (exclude our AP)
    const savedConnections = await $`nmcli -t -f NAME,TYPE connection show`.quiet().text()
    const lines = savedConnections.trim().split("\n")

    const savedWiFiNames: string[] = []
    for (const line of lines) {
      const [name, type] = line.split(":")
      if (type === "802-11-wireless" && name !== AP_CONNECTION_NAME) {
        savedWiFiNames.push(name!)
      }
    }

    if (savedWiFiNames.length === 0) {
      return null
    }

    // Get the actual SSIDs for logging
    const savedSSIDs: string[] = []
    for (const savedName of savedWiFiNames) {
      const connInfo = await $`nmcli -t -f 802-11-wireless.ssid connection show ${savedName}`
        .quiet()
        .nothrow()
        .text()
      const ssid = connInfo.split(":")[1]?.trim()
      if (ssid) {
        savedSSIDs.push(ssid)
      }
    }

    console.log(`[findAvailableSavedNetwork] Saved WiFi networks: ${savedSSIDs.join(", ")}`)

    // Scan for available networks
    const scanResult = await $`nmcli -t -f SSID device wifi list`.quiet().nothrow().text()
    const availableSSIDs = scanResult.trim().split("\n")

    // Check if any saved network is available
    for (const savedName of savedWiFiNames) {
      // NetworkManager connection names often match SSIDs, but let's also check the connection's SSID
      const connInfo = await $`nmcli -t -f 802-11-wireless.ssid connection show ${savedName}`
        .quiet()
        .nothrow()
        .text()
      const ssid = connInfo.split(":")[1]?.trim()

      if (ssid && availableSSIDs.includes(ssid)) {
        console.log(`[findAvailableSavedNetwork] Found available network: ${ssid}`)
        return savedName // Return the connection name
      }
    }

    return null
  } catch (error) {
    console.error("[findAvailableSavedNetwork] ERROR checking for WiFi")
    console.error(error)
    return null
  }
}

async function tryConnect(connectionName: string): Promise<boolean> {
  try {
    console.log(`[tryConnect] Attempting to connect to ${connectionName}...`)
    await $`sudo nmcli connection up ${connectionName}`
    console.log(`[tryConnect] Successfully connected to ${connectionName}`)
    return true
  } catch (error) {
    console.error(`[tryConnect] Failed to connect to ${connectionName}:`, error)
    return false
  }
}

// Initial check
const connected = await isConnectedToWiFi()
console.log(
  `[checkAndManageAP] WiFi: ${connected ? "connected" : "disconnected"}, AP: ${
    apRunning ? "running" : "stopped"
  }`,
)
await checkAndManageAP()

// Check periodically
setInterval(checkAndManageAP, CONFIG.checkInterval)

console.log("Monitor running...")
