/**
 * Shared structured-question contract for local UI, remote channels, and MCP.
 *
 * Purpose: keep every ask_user_questions transport on the same answer shape so
 * gate hooks and LLM-facing JSON do not drift between local TUI, remote
 * Slack/Discord/Telegram, and MCP elicitation paths.
 *
 * Consumer: SF ask_user_questions extension, remote question manager, and
 * structured-question transports.
 */

export interface QuestionOption {
	label: string;
	description: string;
}

export interface Question {
	id: string;
	header: string;
	question: string;
	options: QuestionOption[];
	allowMultiple?: boolean;
}

export interface RoundAnswer {
	selected: string | string[];
	notes: string;
}

export interface RoundResult {
	/** Always false; wrap-up/exit is handled outside a single question round. */
	endInterview: false;
	answers: Record<string, RoundAnswer>;
}

export interface RemoteAnswerLike {
	answers: Record<string, { answers?: string[]; user_note?: string }>;
}

export type ElicitationContentValue = string | number | boolean | string[];

export interface ElicitationResultLike {
	action?: "accept" | "decline" | "cancel" | string;
	content?: Record<string, ElicitationContentValue>;
}

export const DEFAULT_OTHER_OPTION_LABEL = "None of the above";

function normalizeNote(value: ElicitationContentValue | undefined): string {
	return typeof value === "string" ? value.trim() : "";
}

function normalizeSelectedList(
	value: ElicitationContentValue | undefined,
	allowMultiple: boolean,
): string[] {
	if (allowMultiple) {
		return Array.isArray(value)
			? value.filter((item): item is string => typeof item === "string")
			: [];
	}
	return typeof value === "string" && value.length > 0 ? [value] : [];
}

/**
 * Convert local/MCP elicitation form content into the canonical RoundResult.
 *
 * Purpose: preserve the multi-select array contract and "None of the above"
 * notes consistently across transports.
 *
 * Consumer: MCP ask_user_questions handler and any form-based local bridge.
 */
export function roundResultFromElicitationContent(
	questions: readonly Question[],
	result: ElicitationResultLike,
	otherOptionLabel = DEFAULT_OTHER_OPTION_LABEL,
): RoundResult {
	const content = result.content ?? {};
	const answers: Record<string, RoundAnswer> = {};

	for (const question of questions) {
		if (question.allowMultiple) {
			answers[question.id] = {
				selected: normalizeSelectedList(content[question.id], true),
				notes: "",
			};
			continue;
		}

		const list = normalizeSelectedList(content[question.id], false);
		const selected = list[0] ?? "";
		const notes =
			selected === otherOptionLabel
				? normalizeNote(content[`${question.id}__note`])
				: "";
		answers[question.id] = { selected, notes };
	}

	return { endInterview: false, answers };
}

/**
 * Convert a remote-channel answer into the canonical RoundResult.
 *
 * Purpose: remote adapters store answers as `{ answers: string[] }`; consumers
 * need the same `selected` shape as local TUI, especially array preservation for
 * multi-select questions with a single selected item.
 *
 * Consumer: SF remote question manager.
 */
export function roundResultFromRemoteAnswer(
	answer: RemoteAnswerLike,
	questions: readonly Question[],
): RoundResult {
	const allowMultipleById = new Map<string, boolean>();
	for (const question of questions) {
		allowMultipleById.set(question.id, question.allowMultiple ?? false);
	}

	const answers: Record<string, RoundAnswer> = {};
	for (const [id, data] of Object.entries(answer.answers)) {
		const list = data.answers ?? [];
		const allowMultiple = allowMultipleById.get(id) ?? false;
		answers[id] = {
			selected: allowMultiple ? [...list] : (list[0] ?? ""),
			notes: data.user_note ?? "",
		};
	}

	return { endInterview: false, answers };
}

/**
 * Render the canonical RoundResult as the historical LLM/tool JSON payload.
 *
 * Purpose: keep the text response backward-compatible while structured callers
 * consume RoundResult directly.
 *
 * Consumer: ask_user_questions local/remote/MCP handlers.
 */
export function formatRoundResultForTool(result: RoundResult): string {
	const answers: Record<string, { answers: string[] }> = {};
	for (const [id, answer] of Object.entries(result.answers)) {
		const list = Array.isArray(answer.selected)
			? [...answer.selected]
			: [answer.selected];
		if (answer.notes) list.push(`user_note: ${answer.notes}`);
		answers[id] = { answers: list };
	}
	return JSON.stringify({ answers });
}

/**
 * Build the structured content payload shared by MCP and extension details.
 *
 * Purpose: provide the same cancellation and response contract to gate hooks
 * regardless of transport.
 *
 * Consumer: MCP ask_user_questions handler.
 */
export function buildQuestionStructuredContent(
	questions: readonly Question[],
	response: RoundResult | null,
	cancelled: boolean,
): {
	questions: readonly Question[];
	response: RoundResult | null;
	cancelled: boolean;
} {
	return { questions, response, cancelled };
}
