/**
 * OAuth route mounting for external integrations.
 *
 * Provides OAuth2 authorize/callback/disconnect flows for:
 * - Notion (workspace-level integration)
 * - Google (user-level, with token refresh)
 * - ClickUp (workspace-level, task sync)
 *
 * Also provides:
 * - GET /status?space=X — check connection status (no tokens)
 * - GET /sharing?space=X — get sharing config (which spaces each provider shares to)
 * - POST /sharing — update sharing config
 *
 * Tokens are stored in Automerge docs per space via SyncServer.
 */

import { Hono } from 'hono';
import * as Automerge from '@automerge/automerge';
import { notionOAuthRoutes } from './notion';
import { googleOAuthRoutes } from './google';
import { clickupOAuthRoutes } from './clickup';
import { connectionsDocId } from '../../modules/rdocs/schemas';
import { clickupConnectionDocId } from '../../modules/rtasks/schemas';
import { calendarDocId } from '../../modules/rcal/schemas';
import type { ConnectionsDoc } from '../../modules/rdocs/schemas';
import type { ClickUpConnectionDoc } from '../../modules/rtasks/schemas';
import type { CalendarDoc } from '../../modules/rcal/schemas';
import type { SyncServer } from '../local-first/sync-server';

const oauthRouter = new Hono();

let _syncServer: SyncServer | null = null;

export function setOAuthStatusSyncServer(ss: SyncServer) {
	_syncServer = ss;
}

oauthRouter.route('/notion', notionOAuthRoutes);
oauthRouter.route('/google', googleOAuthRoutes);
oauthRouter.route('/clickup', clickupOAuthRoutes);

// GET /status?space=X — return connection status for all providers (no tokens)
oauthRouter.get('/status', (c) => {
	const space = c.req.query('space');
	if (!space) return c.json({ error: 'space query param required' }, 400);
	if (!_syncServer) return c.json({ error: 'SyncServer not initialized' }, 500);

	// Read rDocs connections doc (Google + Notion)
	const connDoc = _syncServer.getDoc<ConnectionsDoc>(connectionsDocId(space));
	// Read rTasks ClickUp connection doc
	const clickupDoc = _syncServer.getDoc<ClickUpConnectionDoc>(clickupConnectionDocId(space));

	const status: Record<string, any> = {};

	// Google — include which services are active
	if (connDoc?.google) {
		// Check how many Google Calendar sources exist for this space
		const calDoc = _syncServer.getDoc<CalendarDoc>(calendarDocId(space));
		const gcalSources = calDoc ? Object.values(calDoc.sources || {}).filter(s => s.sourceType === 'GOOGLE' && s.isActive) : [];

		status.google = {
			connected: true,
			connectedAt: connDoc.google.connectedAt,
			email: connDoc.google.email,
			services: ['Docs', 'Drive', 'Calendar'],
			calendarSources: gcalSources.length,
		};
	} else {
		status.google = { connected: false };
	}

	// Notion
	if (connDoc?.notion) {
		status.notion = {
			connected: true,
			connectedAt: connDoc.notion.connectedAt,
			workspaceName: connDoc.notion.workspaceName,
			services: ['Pages'],
		};
	} else {
		status.notion = { connected: false };
	}

	// ClickUp
	if (clickupDoc?.clickup) {
		status.clickup = {
			connected: true,
			connectedAt: clickupDoc.clickup.connectedAt,
			teamName: clickupDoc.clickup.teamName,
			services: ['Tasks'],
		};
	} else {
		status.clickup = { connected: false };
	}

	// File-based connectors (always available, no OAuth)
	status.obsidian = { connected: true, type: 'file', note: 'Upload vault ZIP in rDocs or rNotes' };
	status.logseq = { connected: true, type: 'file', note: 'Upload vault ZIP in rDocs or rNotes' };

	return c.json(status);
});

// ── Sharing config ──
// Stored as an Automerge doc: {userSpace}:oauth:sharing
interface SharingDoc {
	meta: { module: string; collection: string; version: number; spaceSlug: string; createdAt: number };
	sharing?: Record<string, { spaces: string[] }>; // e.g. { google: { spaces: ['team-x', 'dao-y'] } }
}

function sharingDocId(userSpace: string) {
	return `${userSpace}:oauth:sharing` as const;
}

function ensureSharingDoc(userSpace: string): SharingDoc {
	if (!_syncServer) throw new Error('SyncServer not initialized');
	const docId = sharingDocId(userSpace);
	let doc = _syncServer.getDoc<SharingDoc>(docId);
	if (!doc) {
		doc = Automerge.change(Automerge.init<SharingDoc>(), 'init oauth sharing', (d) => {
			d.meta = { module: 'oauth', collection: 'sharing', version: 1, spaceSlug: userSpace, createdAt: Date.now() };
			d.sharing = {} as any;
		});
		_syncServer.setDoc(docId, doc);
	}
	return doc;
}

// GET /sharing?space=X — get sharing config for user's personal space
oauthRouter.get('/sharing', (c) => {
	const space = c.req.query('space');
	if (!space) return c.json({ error: 'space query param required' }, 400);
	if (!_syncServer) return c.json({ error: 'SyncServer not initialized' }, 500);

	const doc = _syncServer.getDoc<SharingDoc>(sharingDocId(space));
	return c.json(doc?.sharing || {});
});

// POST /sharing — update sharing config
// Body: { space: string, provider: string, sharedSpaces: string[] }
oauthRouter.post('/sharing', async (c) => {
	const body = await c.req.json<{ space: string; provider: string; sharedSpaces: string[] }>();
	if (!body.space || !body.provider || !Array.isArray(body.sharedSpaces)) {
		return c.json({ error: 'space, provider, and sharedSpaces[] required' }, 400);
	}
	if (!_syncServer) return c.json({ error: 'SyncServer not initialized' }, 500);

	ensureSharingDoc(body.space);
	const docId = sharingDocId(body.space);

	_syncServer.changeDoc<SharingDoc>(docId, `Update ${body.provider} sharing`, (d) => {
		if (!d.sharing) d.sharing = {} as any;
		if (!d.sharing![body.provider]) d.sharing![body.provider] = { spaces: [] } as any;
		d.sharing![body.provider].spaces = body.sharedSpaces as any;
	});

	return c.json({ ok: true });
});

export { oauthRouter };
