#!/usr/bin/env node
// @ts-check

console.log("-=- This script is experimental. It WILL mess up the room history on Matrix. -=-")
console.log()

const {channel: channelID} = require("minimist")(process.argv.slice(2), {string: ["channel"]})
if (!channelID) {
	console.error("Usage: ./scripts/backfill.js --channel=<channel id here>")
	process.exit(1)
}

const sqlite = require("better-sqlite3")
const backfill = new sqlite("scripts/backfill.db")
backfill.prepare("CREATE TABLE IF NOT EXISTS backfill (channel_id TEXT NOT NULL, message_id INTEGER NOT NULL, PRIMARY KEY (channel_id, message_id))").run()

const HeatSync = require("heatsync")

const {reg} = require("../src/matrix/read-registration")
const passthrough = require("../src/passthrough")

const sync = new HeatSync({watchFS: false})
const db = new sqlite("ooye.db")
Object.assign(passthrough, {sync, db})

const DiscordClient = require("../src/d2m/discord-client")

const discord = new DiscordClient(reg.ooye.discord_token, "half")
passthrough.discord = discord

const {as} = require("../src/matrix/appservice")
passthrough.as = as

const orm = sync.require("../src/db/orm")
passthrough.from = orm.from
passthrough.select = orm.select

/** @type {import("../src/d2m/event-dispatcher")}*/
const eventDispatcher = sync.require("../src/d2m/event-dispatcher")
/** @type {import("../src/d2m/actions/create-room")} */
const createRoom = sync.require("../src/d2m/actions/create-room")

;(async () => {
	await discord.cloud.connect()
	console.log("Connected, waiting for data about requested channel...")

	discord.cloud.on("event", event)
})()

const preparedInsert = backfill.prepare("INSERT INTO backfill (channel_id, message_id) VALUES (?, ?)")

async function event(event) {
	if (event.t !== "GUILD_CREATE") return
	const channel = event.d.channels.find(c => c.id === channelID)
	if (!channel) return
	const guild_id = event.d.id

	try {
		await createRoom.syncRoom(channelID)
		let last = backfill.prepare("SELECT cast(max(message_id) as TEXT) FROM backfill WHERE channel_id = ?").pluck().get(channelID) || "0"
		console.log(`OK, processing messages for #${channel.name}, continuing from ${last}`)

		while (last) {
			const messages = await discord.snow.channel.getChannelMessages(channelID, {limit: 50, after: String(last)})
			messages.reverse() // More recent messages come first -> More recent messages come last
			for (const message of messages) {
				const simulatedGatewayDispatchData = {
					guild_id,
					backfill: true,
					...message
				}
				await eventDispatcher.MESSAGE_CREATE(discord, simulatedGatewayDispatchData)
				preparedInsert.run(channelID, message.id)
			}
			last = messages.at(-1)?.id
		}

		process.exit()
	} catch (e) {
		console.error(e)
		process.exit(1) // won't exit automatically on thrown error due to living discord connection, so manual exit is necessary
	}
}
