// Fetch the list of configured devices from the Homebridge UI API
import { isValidDeviceType, normalizeDeviceType } from '../../../device-types.js'
import './types.js'
import { uiLog } from './logger.js'
import { toastError } from './toast.js'

export async function fetchDevices(): Promise<any[]> {
  try {
    if (typeof homebridge.getPluginConfig !== 'function') {
      throw new TypeError('Homebridge UI API not available')
    }
    const configArr = await homebridge.getPluginConfig()
    const config = Array.isArray(configArr) && configArr.length > 0 ? configArr.find(isSwitchBotPlatformConfig) : null
    if (!config || !Array.isArray(config.devices)) {
      return []
    }
    return config.devices
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e)
    uiLog.error('Error fetching devices:', msg)
    return []
  }
}

/**
 * Validate and auto-correct device types in the config array before saving.
 * Returns an array of errors for devices that cannot be fixed.
 */
export function validateAndFixDeviceTypes(devices: Array<{ deviceId: string, configDeviceName: string, configDeviceType: string }>) {
  const errors: Array<{ deviceId: string, name: string, type: string }> = []
  for (const d of devices) {
    if (!isValidDeviceType(d.configDeviceType)) {
      const fixed = normalizeDeviceType(d.configDeviceType)
      if (fixed) {
        d.configDeviceType = fixed
      } else {
        errors.push({
          deviceId: d.deviceId,
          name: d.configDeviceName,
          type: d.configDeviceType,
        })
      }
    }
  }
  return errors
}

// API wrapper functions for communicating with the Homebridge UI server

function isSwitchBotPlatformConfig(block: any): boolean {
  const platformName = String(block?.platform || block?.name || '').toLowerCase()
  return (
    platformName === 'switchbot'
    || platformName === '@switchbot/homebridge-switchbot'
    || platformName.includes('switchbot')
  )
}

export async function syncParentPluginConfigFromDisk(autoSave = false): Promise<boolean> {
  try {
    if (
      typeof homebridge.getPluginConfig !== 'function'
      || typeof homebridge.updatePluginConfig !== 'function'
    ) {
      uiLog.warn('Parent config sync API not available')
      return false
    }

    // Use Homebridge UI API to fetch and update config
    const pluginConfigBlocks = await homebridge.getPluginConfig()
    if (!Array.isArray(pluginConfigBlocks) || !pluginConfigBlocks.length) {
      uiLog.warn('No plugin config blocks returned from Homebridge')
      return false
    }

    const index = pluginConfigBlocks.findIndex(block => isSwitchBotPlatformConfig(block))
    if (index < 0) {
      uiLog.warn('SwitchBot platform block not found in Homebridge plugin config')
      return false
    }

    // Validate and fix device types before saving
    const errors = validateAndFixDeviceTypes(pluginConfigBlocks[index].devices || [])
    if (errors.length > 0) {
      toastError(`Invalid device types found: ${errors.map(e => `${e.name} (${e.type})`).join(', ')}`)
      return false
    }
    // pluginConfigBlocks[index] is already up to date
    await homebridge.updatePluginConfig(pluginConfigBlocks)

    // Auto-save to disk if requested - prevents parent UI from overwriting with stale cache
    if (autoSave && typeof homebridge.savePluginConfig === 'function') {
      uiLog.info('Auto-saving config to disk...')
      await homebridge.savePluginConfig()
      uiLog.info('Config saved successfully')
    }

    return true
  } catch (e) {
    uiLog.warn('Failed to sync parent plugin config cache:', e)
    return false
  }
}

export async function fetchCredentialStatus(): Promise<any> {
  try {
    const resp = await homebridge.request('/credentials', {})
    uiLog.info('Load credentials response:', resp)

    if (!resp || resp.success === false) {
      uiLog.error('Failed to load credentials:', resp)
      return null
    }

    return resp.data || {}
  } catch (e) {
    uiLog.error('Error loading credentials:', e)
    return null
  }
}

export async function saveCredentials(token: string, secret: string): Promise<any> {
  uiLog.info('Saving credentials...')
  const resp = await homebridge.request('/credentials', { token, secret })
  uiLog.info('Save response:', resp)
  if (!resp || resp.success === false) {
    throw new Error(resp?.message || 'Save failed')
  }
  return resp.data || resp
}

export interface DiscoverRequestOptions {
  bleEnabled?: boolean
  bleScanDurationSeconds?: number
  bleTimeoutSeconds?: number
}

export async function discoverDevices(
  mode: 'all' | 'ble' | 'openapi' = 'all',
  options?: DiscoverRequestOptions,
): Promise<any[]> {
  const resp = await homebridge.request('/discover', { mode, ...options })
  uiLog.info('Discover response:', resp)
  if (!resp || resp.success === false) {
    throw new Error(resp?.data?.message || 'Discovery failed')
  }
  return resp.data || []
}

export async function fetchBluetoothStatus(): Promise<{ available: boolean, message: string }> {
  try {
    const resp = await homebridge.request('/ble-status', {})
    if (!resp || resp.success === false) {
      return { available: false, message: 'Bluetooth status unavailable' }
    }
    return resp.data || { available: false, message: 'Bluetooth status unavailable' }
  } catch (_e) {
    return { available: false, message: 'Bluetooth status unavailable' }
  }
}

export async function testDeviceConnection(payload: {
  deviceId: string
  connectionType?: string
  address?: string
}): Promise<{
  success: boolean
  deviceId: string
  method: string
  latencyMs: number
  message: string
  state?: Record<string, any>
}> {
  const resp = await homebridge.request('/test-connection', payload)
  if (!resp || resp.success === false) {
    throw new Error(resp?.data?.message || 'Connection test failed')
  }

  return resp.data || {
    success: false,
    deviceId: payload.deviceId,
    method: 'Auto',
    latencyMs: 0,
    message: 'Connection test failed',
  }
}

export async function addDevice(
  deviceId: string,
  name: string,
  type: string,
  options?: { address?: string, model?: string, rssi?: number, encryptionKey?: string, keyId?: string },
): Promise<any> {
  if (typeof homebridge.getPluginConfig !== 'function' || typeof homebridge.updatePluginConfig !== 'function') {
    throw new TypeError('Homebridge UI API not available')
  }
  const configArr = await homebridge.getPluginConfig()
  const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1
  if (idx === -1) {
    throw new Error('SwitchBot config not found')
  }
  const config = configArr[idx]
  if (!Array.isArray(config.devices)) {
    config.devices = []
  }
  const normalizedDeviceId = String(deviceId).trim().toLowerCase()
  const exists = config.devices.some((d: any) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId)
  if (exists) {
    return { alreadyExists: true, message: 'Device already in config' }
  }
  const newDevice: any = { deviceId, configDeviceName: name, configDeviceType: type }
  if (options?.address) {
    newDevice.address = options.address
  }
  if (options?.model) {
    newDevice.model = options.model
  }
  if (options?.rssi !== undefined && options?.rssi !== null && options?.rssi !== 0) {
    newDevice.rssi = options.rssi
  }
  if (options?.encryptionKey) {
    newDevice.encryptionKey = options.encryptionKey
  }
  if (options?.keyId) {
    newDevice.keyId = options.keyId
  }
  config.devices.push(newDevice)
  await homebridge.updatePluginConfig(configArr)
  if (typeof homebridge.savePluginConfig === 'function') {
    await homebridge.savePluginConfig()
  }
  return { added: true, message: `Device "${name}" added successfully` }
}

export async function addDevicesInBulk(
  devices: Array<{ deviceId: string, name: string, type: string, rssi?: number, address?: string, model?: string }>,
): Promise<any> {
  const resp = await homebridge.request('/add-devices', { devices })
  uiLog.info('Bulk add response:', resp)
  if (!resp || resp.success === false) {
    throw new Error(resp?.data?.message || 'Bulk add failed')
  }
  return normalizeBulkAddDevicesResponse(resp)
}

export function normalizeBulkAddDevicesResponse(resp: any): any {
  const payload = resp?.data && typeof resp.data === 'object' ? resp.data : resp
  const addedCount = Number(payload?.addedCount ?? payload?.added ?? 0)
  const skippedCount = Number(payload?.skippedCount ?? payload?.skipped ?? 0)
  const updatedCount = Number(payload?.updatedCount ?? payload?.updated ?? 0)

  return {
    ...payload,
    success: resp?.success ?? true,
    addedCount,
    skippedCount,
    updatedCount,
  }
}

export async function updateDevice(
  deviceId: string,
  configDeviceName?: string,
  configDeviceType?: string,
  options?: {
    refreshRate?: number
    connectionPreference?: string
    encryptionKey?: string
    keyId?: string
    room?: string
    [key: string]: any
  },
): Promise<any> {
  if (typeof homebridge.getPluginConfig !== 'function' || typeof homebridge.updatePluginConfig !== 'function') {
    throw new TypeError('Homebridge UI API not available')
  }
  const configArr = await homebridge.getPluginConfig()
  const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1
  if (idx === -1) {
    throw new Error('SwitchBot config not found')
  }
  const config = configArr[idx]
  if (!Array.isArray(config.devices)) {
    throw new TypeError('No devices array in config')
  }
  const normalizedDeviceId = String(deviceId).trim().toLowerCase()
  const device = config.devices.find((d: any) => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() === normalizedDeviceId)
  if (!device) {
    throw new Error('Device not found in config')
  }
  if (configDeviceName) {
    device.configDeviceName = configDeviceName
  }
  if (configDeviceType) {
    device.configDeviceType = configDeviceType
  }
  if (options) {
    Object.assign(device, options)
  }
  await homebridge.updatePluginConfig(configArr)
  if (typeof homebridge.savePluginConfig === 'function') {
    await homebridge.savePluginConfig()
  }
  return { updated: true, message: `Device updated successfully` }
}

export async function deleteDevice(deviceId: string): Promise<any> {
  if (typeof homebridge.getPluginConfig !== 'function' || typeof homebridge.updatePluginConfig !== 'function') {
    throw new TypeError('Homebridge UI API not available')
  }
  const configArr = await homebridge.getPluginConfig()
  const idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1
  if (idx === -1) {
    throw new Error('SwitchBot config not found')
  }
  const config = configArr[idx]
  if (!Array.isArray(config.devices)) {
    throw new TypeError('No devices array in config')
  }
  const normalizedDeviceId = String(deviceId).trim().toLowerCase()
  const before = config.devices.length
  // Remove the target device
  config.devices = config.devices.filter(d => String(d.deviceId ?? d.id ?? '').trim().toLowerCase() !== normalizedDeviceId)
  // Defensive: filter out any invalid device entries (missing required fields)
  config.devices = config.devices.filter(d => d && typeof d === 'object' && d.deviceId && d.configDeviceType)
  if (config.devices.length === before) {
    throw new Error('Device not found in config')
  }
  await homebridge.updatePluginConfig(configArr)
  if (typeof homebridge.savePluginConfig === 'function') {
    await homebridge.savePluginConfig()
  }
  return { deleted: true, message: `Device removed from config` }
}

export async function deleteAllDevices(): Promise<any> {
  if (typeof homebridge.getPluginConfig !== 'function' || typeof homebridge.updatePluginConfig !== 'function') {
    throw new TypeError('Homebridge UI API not available')
  }
  const configArr = await homebridge.getPluginConfig()
  // Find or create the SwitchBot config block
  let idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1
  if (idx === -1) {
    // If not found, create a new config block for SwitchBot
    const newBlock = { platform: 'SwitchBot', devices: [] }
    configArr.push(newBlock)
    idx = configArr.length - 1
  }
  const config = configArr[idx]
  // Always ensure devices is an array
  if (!Array.isArray(config.devices)) {
    config.devices = []
  }
  const deletedCount = config.devices.length
  config.devices = []
  // Defensive: ensure required fields for schema compliance
  if (!config.platform) {
    config.platform = 'SwitchBot'
  }
  // Ensure 'name' property is present (required by schema for Homebridge platform blocks)
  if (!config.name) {
    config.name = 'SwitchBot'
  }
  // Save updated config
  await homebridge.updatePluginConfig(configArr)
  if (typeof homebridge.savePluginConfig === 'function') {
    await homebridge.savePluginConfig()
  }
  return { deleted: true, deletedCount, message: `Removed ${deletedCount} device(s) from config` }
}
