const DEVICE_TYPES = Object.freeze(['alpr', 'nvr', 'doorbell', 'feed', 'traffic', 'ip', 'drone'])
const SOURCE_TYPES = Object.freeze(['mjpeg', 'hls'])

const sanitizeStreamUrl = (url) => {
  if (typeof url !== 'string' || !url.trim()) return ''
  const u = url.trim()
  return (u.startsWith('https://') || u.startsWith('http://')) ? u : ''
}

/** @typedef {{ id: string, name: string, device_type: string, vendor: string | null, lat: number, lng: number, stream_url: string, source_type: string, config: string | null }} DeviceRow */

/**
 * @param {string} s
 * @returns {string} 'mjpeg' or 'hls'
 */
function normalizeSourceType(s) {
  return SOURCE_TYPES.includes(s) ? s : 'mjpeg'
}

/**
 * @param {unknown} row
 * @returns {DeviceRow | null} Normalized device row or null if invalid
 */
export function rowToDevice(row) {
  if (!row || typeof row !== 'object') return null
  const r = /** @type {Record<string, unknown>} */ (row)
  if (typeof r.id !== 'string' || typeof r.name !== 'string' || typeof r.device_type !== 'string') return null
  if (typeof r.lat !== 'number' && typeof r.lat !== 'string') return null
  if (typeof r.lng !== 'number' && typeof r.lng !== 'string') return null
  const lat = Number(r.lat)
  const lng = Number(r.lng)
  if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null
  return {
    id: r.id,
    name: r.name,
    device_type: r.device_type,
    vendor: typeof r.vendor === 'string' ? r.vendor : null,
    lat,
    lng,
    stream_url: typeof r.stream_url === 'string' ? r.stream_url : '',
    source_type: normalizeSourceType(r.source_type),
    config: typeof r.config === 'string' ? r.config : null,
  }
}

/**
 * Sanitize device for API response (safe stream URL, valid sourceType).
 * @param {DeviceRow} device
 * @returns {{ id: string, name: string, device_type: string, vendor: string | null, lat: number, lng: number, streamUrl: string, sourceType: string, config: string | null }} Sanitized device for API response
 */
export function sanitizeDeviceForResponse(device) {
  return {
    id: device.id,
    name: device.name,
    device_type: device.device_type,
    vendor: device.vendor,
    lat: device.lat,
    lng: device.lng,
    streamUrl: sanitizeStreamUrl(device.stream_url),
    sourceType: normalizeSourceType(device.source_type),
    config: device.config,
  }
}

/**
 * Validate and normalize device body for POST.
 * @param {unknown} body
 * @returns {{ name: string, device_type: string, vendor: string | null, lat: number, lng: number, stream_url: string, source_type: string, config: string | null }} Validated and normalized body fields
 */
export function validateDeviceBody(body) {
  if (!body || typeof body !== 'object') throw createError({ statusCode: 400, message: 'body required' })
  const b = /** @type {Record<string, unknown>} */ (body)
  const name = typeof b.name === 'string' ? b.name.trim() || '' : ''
  const deviceType = typeof b.device_type === 'string' && DEVICE_TYPES.includes(b.device_type) ? b.device_type : 'feed'
  const vendor = typeof b.vendor === 'string' ? b.vendor.trim() || null : null
  const lat = Number(b.lat)
  const lng = Number(b.lng)
  if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
    throw createError({ statusCode: 400, message: 'lat and lng required as finite numbers' })
  }
  const streamUrl = typeof b.stream_url === 'string' ? b.stream_url.trim() : ''
  const sourceType = normalizeSourceType(b.source_type)
  const config = typeof b.config === 'string' ? b.config : (b.config != null ? JSON.stringify(b.config) : null)
  return { name, device_type: deviceType, vendor, lat, lng, stream_url: streamUrl, source_type: sourceType, config }
}

export { DEVICE_TYPES, SOURCE_TYPES }
