import type { RealtimeEvent as HostRealtimeEvent } from '@zync/realtime'
import type { RealtimeEvent as PlatformRealtimeEvent } from '@platform-modules/realtime'
import {
  makeQueueConsumer,
  publishEvent,
  verifyInternalSecret,
} from '@platform-modules/realtime/server'
import type { Env } from '@zync/types'

type HostRealtimeEventInput = Omit<HostRealtimeEvent, 'id' | 'timestamp'>

function toPlatformRealtimeEvent(
  event: HostRealtimeEvent,
): PlatformRealtimeEvent<HostRealtimeEvent['type'], HostRealtimeEvent['payload']> {
  return {
    id: event.id,
    type: event.type,
    scope: event.tenantId,
    ...(event.targetUserId ? { targetUserId: event.targetUserId } : {}),
    payload: event.payload,
    timestamp: event.timestamp,
  }
}

function toHostRealtimeEvent(
  event: PlatformRealtimeEvent<HostRealtimeEvent['type'], HostRealtimeEvent['payload']>,
): HostRealtimeEvent {
  return {
    id: event.id,
    type: event.type,
    tenantId: event.scope,
    ...(event.targetUserId ? { targetUserId: event.targetUserId } : {}),
    payload: event.payload,
    timestamp: event.timestamp,
  }
}

export async function publishPlatformRealtimeEvent(
  queue: Queue,
  event: HostRealtimeEventInput,
): Promise<void> {
  await publishEvent(queue, {
    type: event.type,
    scope: event.tenantId,
    ...(event.targetUserId ? { targetUserId: event.targetUserId } : {}),
    payload: event.payload,
  })
}

export async function dispatchPlatformRealtimeEvent(
  env: Pick<Env, 'DO_REALTIME'>,
  event: HostRealtimeEvent,
): Promise<void> {
  const id = env.DO_REALTIME.idFromName(`tenant:${event.tenantId}`)
  const stub = env.DO_REALTIME.get(id)

  const response = await stub.fetch('https://do/broadcast', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(event),
  })

  if (!response.ok) {
    throw new Error(`Realtime fanout failed with status ${response.status}`)
  }
}

export const handlePlatformRealtimeBatch = makeQueueConsumer<
  PlatformRealtimeEvent<HostRealtimeEvent['type'], HostRealtimeEvent['payload']>
>(async (event, runtimeEnv) => {
  await dispatchPlatformRealtimeEvent(
    runtimeEnv as Pick<Env, 'DO_REALTIME'>,
    toHostRealtimeEvent(event),
  )
})

export function verifyPlatformRealtimeInternalSecret(
  provided: string | null,
  expected: string,
): boolean {
  return verifyInternalSecret(provided, expected)
}

export { toPlatformRealtimeEvent }
