/**
 * Migration: rTime TasksDoc → rTasks BoardDoc + WeavingDoc
 *
 * Reads all {space}:rtime:tasks docs and:
 * 1. Creates TaskItem entries in the rTasks board (reusing Task.id)
 * 2. Creates WeavingOverlay entries in the WeavingDoc
 * 3. Moves connections + execStates from TasksDoc → WeavingDoc
 *
 * Usage: npx tsx scripts/migrate-rtime-tasks.ts [space]
 * Default space: demo
 *
 * This script must be run on the server where Automerge data lives.
 * It operates on the SyncServer data files directly.
 */

import * as Automerge from '@automerge/automerge';
import type { SyncServer } from '../server/local-first/sync-server';
import {
	tasksDocId, weavingDocId, weavingSchema,
} from '../modules/rtime/schemas';
import type { TasksDoc, WeavingDoc, Task, Connection, ExecState } from '../modules/rtime/schemas';
import { boardDocId, createTaskItem, boardSchema } from '../modules/rtasks/schemas';
import type { BoardDoc, TaskItem } from '../modules/rtasks/schemas';

const space = process.argv[2] || 'demo';

console.log(`[migrate] Starting rTime → rTasks migration for space: ${space}`);

/**
 * Standalone migration logic. Call with a SyncServer instance.
 * This is exported so it can also be called from server startup if needed.
 */
export function migrateRTimeTasks(syncServer: SyncServer, spaceSlug: string): {
	tasksCreated: number;
	overlaysCreated: number;
	connectionsMoved: number;
	execStatesMoved: number;
} {
	const result = { tasksCreated: 0, overlaysCreated: 0, connectionsMoved: 0, execStatesMoved: 0 };

	// 1. Read legacy TasksDoc
	const oldDocId = tasksDocId(spaceSlug);
	const oldDoc = syncServer.getDoc<TasksDoc>(oldDocId);
	if (!oldDoc) {
		console.log(`[migrate] No TasksDoc found at ${oldDocId}, nothing to migrate.`);
		return result;
	}

	const oldTasks = Object.values(oldDoc.tasks || {});
	const oldConnections = Object.values(oldDoc.connections || {});
	const oldExecStates = Object.values(oldDoc.execStates || {});

	if (oldTasks.length === 0 && oldConnections.length === 0) {
		console.log(`[migrate] TasksDoc is empty, nothing to migrate.`);
		return result;
	}

	console.log(`[migrate] Found ${oldTasks.length} tasks, ${oldConnections.length} connections, ${oldExecStates.length} exec states`);

	// 2. Ensure rTasks board exists
	const bDocId = boardDocId(spaceSlug, spaceSlug);
	let boardDoc = syncServer.getDoc<BoardDoc>(bDocId);
	if (!boardDoc) {
		boardDoc = Automerge.change(Automerge.init<BoardDoc>(), 'init board for migration', (d) => {
			const init = boardSchema.init();
			Object.assign(d, init);
			d.meta.spaceSlug = spaceSlug;
			d.board.id = spaceSlug;
			d.board.slug = spaceSlug;
			d.board.name = `${spaceSlug} Board`;
		});
		syncServer.setDoc(bDocId, boardDoc);
		console.log(`[migrate] Created rTasks board: ${bDocId}`);
	}

	// 3. Create TaskItem for each rTime Task (reuse ID)
	for (const task of oldTasks) {
		if (boardDoc.tasks[task.id]) {
			console.log(`[migrate] Task ${task.id} already exists in board, skipping.`);
			continue;
		}
		const taskItem = createTaskItem(task.id, spaceSlug, task.name, {
			description: task.description || '',
		});
		syncServer.changeDoc<BoardDoc>(bDocId, `migrate task: ${task.name}`, (d) => {
			d.tasks[task.id] = taskItem as any;
		});
		result.tasksCreated++;
	}

	// 4. Ensure WeavingDoc exists
	const wDocId = weavingDocId(spaceSlug);
	let wDoc = syncServer.getDoc<WeavingDoc>(wDocId);
	if (!wDoc) {
		wDoc = Automerge.change(Automerge.init<WeavingDoc>(), 'init weaving for migration', (d) => {
			const init = weavingSchema.init();
			Object.assign(d, init);
			d.meta.spaceSlug = spaceSlug;
			d.boardSlug = spaceSlug;
		});
		syncServer.setDoc(wDocId, wDoc);
	}

	// 5. Create WeavingOverlay for each task (with needs, notes, links)
	let canvasX = 300;
	for (const task of oldTasks) {
		if (wDoc.weavingOverlays[task.id]) {
			console.log(`[migrate] Overlay for ${task.id} already exists, skipping.`);
			continue;
		}
		syncServer.changeDoc<WeavingDoc>(wDocId, `migrate overlay: ${task.name}`, (d) => {
			d.weavingOverlays[task.id] = {
				rtasksId: task.id,
				needs: task.needs || {},
				canvasX,
				canvasY: 150,
				notes: task.notes || '',
				links: task.links || [],
				intentFrameId: task.intentFrameId,
			} as any;
		});
		canvasX += 280;
		result.overlaysCreated++;
	}

	// 6. Move connections from TasksDoc → WeavingDoc
	for (const conn of oldConnections) {
		syncServer.changeDoc<WeavingDoc>(wDocId, `migrate connection: ${conn.id}`, (d) => {
			if (!d.connections[conn.id]) {
				d.connections[conn.id] = { ...conn } as any;
				result.connectionsMoved++;
			}
		});
	}

	// 7. Move execStates from TasksDoc → WeavingDoc
	for (const es of oldExecStates) {
		syncServer.changeDoc<WeavingDoc>(wDocId, `migrate exec state: ${es.taskId}`, (d) => {
			if (!d.execStates[es.taskId]) {
				d.execStates[es.taskId] = { ...es } as any;
				result.execStatesMoved++;
			}
		});
	}

	// Refresh doc after changes
	const finalW = syncServer.getDoc<WeavingDoc>(wDocId)!;
	result.connectionsMoved = Object.keys(finalW.connections).length;
	result.execStatesMoved = Object.keys(finalW.execStates).length;

	console.log(`[migrate] Migration complete:
  Tasks created in rTasks: ${result.tasksCreated}
  Weaving overlays created: ${result.overlaysCreated}
  Connections moved: ${result.connectionsMoved}
  Exec states moved: ${result.execStatesMoved}`);

	return result;
}

// CLI entry point — only runs when executed directly
if (process.argv[1]?.includes('migrate-rtime-tasks')) {
	console.log('[migrate] This script must be imported and called with a SyncServer instance.');
	console.log('[migrate] Example: import { migrateRTimeTasks } from "./scripts/migrate-rtime-tasks";');
	console.log('[migrate]          migrateRTimeTasks(syncServer, "demo");');
}
