/**
 * Bidirectional mapping between rTasks and ClickUp fields.
 *
 * Pure functions — no side effects, no API calls.
 */

// ── Status mapping ──

const DEFAULT_STATUS_TO_CLICKUP: Record<string, string> = {
	TODO: 'to do',
	IN_PROGRESS: 'in progress',
	REVIEW: 'in review',
	DONE: 'complete',
};

const DEFAULT_CLICKUP_TO_STATUS: Record<string, string> = {
	'to do': 'TODO',
	'open': 'TODO',
	'pending': 'TODO',
	'in progress': 'IN_PROGRESS',
	'in review': 'REVIEW',
	'review': 'REVIEW',
	'complete': 'DONE',
	'closed': 'DONE',
	'done': 'DONE',
};

export function toClickUpStatus(
	rTasksStatus: string,
	customMap?: Record<string, string>,
): string {
	if (customMap?.[rTasksStatus]) return customMap[rTasksStatus];
	return DEFAULT_STATUS_TO_CLICKUP[rTasksStatus] || rTasksStatus.toLowerCase().replace(/_/g, ' ');
}

export function fromClickUpStatus(
	clickUpStatus: string,
	reverseMap?: Record<string, string>,
): string {
	const lower = clickUpStatus.toLowerCase();
	if (reverseMap?.[lower]) return reverseMap[lower];
	if (DEFAULT_CLICKUP_TO_STATUS[lower]) return DEFAULT_CLICKUP_TO_STATUS[lower];
	// Fuzzy: check if any known keyword is contained
	for (const [pattern, mapped] of Object.entries(DEFAULT_CLICKUP_TO_STATUS)) {
		if (lower.includes(pattern)) return mapped;
	}
	return 'TODO'; // fallback
}

// ── Priority mapping ──

const PRIORITY_TO_CLICKUP: Record<string, number> = {
	URGENT: 1,
	HIGH: 2,
	MEDIUM: 3,
	LOW: 4,
};

const CLICKUP_TO_PRIORITY: Record<number, string> = {
	1: 'URGENT',
	2: 'HIGH',
	3: 'MEDIUM',
	4: 'LOW',
};

export function toClickUpPriority(priority: string | null): number | null {
	if (!priority) return null;
	return PRIORITY_TO_CLICKUP[priority] ?? 3;
}

export function fromClickUpPriority(cuPriority: number | null | undefined): string | null {
	if (cuPriority == null) return null;
	return CLICKUP_TO_PRIORITY[cuPriority] ?? 'MEDIUM';
}

// ── Content hashing for change detection ──

export async function contentHash(parts: {
	title: string;
	description: string;
	status: string;
	priority: string | null;
}): Promise<string> {
	const raw = `${parts.title}\x00${parts.description}\x00${parts.status}\x00${parts.priority ?? ''}`;
	const buf = new TextEncoder().encode(raw);
	const hash = await crypto.subtle.digest('SHA-256', buf);
	return Array.from(new Uint8Array(hash)).map(b => b.toString(16).padStart(2, '0')).join('');
}

// ── Conflict detection ──

export interface FieldDiff {
	field: string;
	local: string;
	remote: string;
}

export function detectConflicts(
	localFields: { title: string; description: string; status: string; priority: string | null },
	remoteFields: { title: string; description: string; status: string; priority: string | null },
	baseFields: { title: string; description: string; status: string; priority: string | null },
): { conflicts: FieldDiff[]; localOnly: string[]; remoteOnly: string[] } {
	const conflicts: FieldDiff[] = [];
	const localOnly: string[] = [];
	const remoteOnly: string[] = [];

	for (const field of ['title', 'description', 'status', 'priority'] as const) {
		const base = baseFields[field] ?? '';
		const local = localFields[field] ?? '';
		const remote = remoteFields[field] ?? '';

		const localChanged = local !== base;
		const remoteChanged = remote !== base;

		if (localChanged && remoteChanged && local !== remote) {
			conflicts.push({ field, local, remote });
		} else if (localChanged && !remoteChanged) {
			localOnly.push(field);
		} else if (!localChanged && remoteChanged) {
			remoteOnly.push(field);
		}
	}

	return { conflicts, localOnly, remoteOnly };
}

// ── ClickUp task → rTasks fields ──

export function mapClickUpTaskToRTasks(cuTask: any, reverseStatusMap?: Record<string, string>): {
	title: string;
	description: string;
	status: string;
	priority: string | null;
	labels: string[];
	clickUpMeta: {
		taskId: string;
		listId: string;
		url: string;
	};
} {
	return {
		title: cuTask.name || 'Untitled',
		description: cuTask.description || cuTask.text_content || '',
		status: fromClickUpStatus(cuTask.status?.status || 'to do', reverseStatusMap),
		priority: fromClickUpPriority(cuTask.priority?.id ? Number(cuTask.priority.id) : null),
		labels: (cuTask.tags || []).map((t: any) => t.name),
		clickUpMeta: {
			taskId: cuTask.id,
			listId: cuTask.list?.id || '',
			url: cuTask.url || `https://app.clickup.com/t/${cuTask.id}`,
		},
	};
}

// ── rTasks fields → ClickUp API body ──

export function mapRTasksToClickUpBody(
	task: { title: string; description: string; status: string; priority: string | null; labels: string[] },
	statusMap?: Record<string, string>,
): Record<string, any> {
	const body: Record<string, any> = {
		name: task.title,
		description: task.description,
		status: toClickUpStatus(task.status, statusMap),
	};
	const p = toClickUpPriority(task.priority);
	if (p != null) body.priority = p;
	if (task.labels?.length) body.tags = task.labels;
	return body;
}

// ── Build reverse status map from ClickUp list statuses ──

export function buildStatusMaps(clickUpStatuses: Array<{ status: string; type: string }>): {
	statusMap: Record<string, string>;
	reverseStatusMap: Record<string, string>;
} {
	const statusMap: Record<string, string> = {};
	const reverseStatusMap: Record<string, string> = {};

	for (const s of clickUpStatuses) {
		const mapped = fromClickUpStatus(s.status);
		reverseStatusMap[s.status.toLowerCase()] = mapped;
		// First ClickUp status for each rTasks status wins
		if (!statusMap[mapped]) statusMap[mapped] = s.status;
	}

	return { statusMap, reverseStatusMap };
}
