import {
	TableType,
} from "qrc:/js/lib/generated/enum";
import {
	isCadFeature,
	isScrewThread,
} from "qrc:/js/lib/generated/typeguard";
import {
	front,
} from "./array_util";

import {
	getTable,
} from "./table_utils";
import {
	assert,
	isArray,
	isInstanceOf,
} from "./utils";

export interface TappingCandidate {
	cadFeature: CadFeature;
	matchingScrewThreads: ScrewThread[];
}

export function isTappingCandidate(arg: unknown): arg is TappingCandidate {
	return isInstanceOf<TappingCandidate>(arg, {
		cadFeature: isCadFeature,
		matchingScrewThreads: (arg: unknown): arg is ScrewThread[] => isArray(arg, isScrewThread),
	});
}

export interface TappingSceneCandidate extends TappingCandidate {
	/**
	 * Center of the associated core hole in Scene / TwoDimRep coordinates
	 */
	center2: Point2;
}

export interface TappingSceneSelectionEntry {
	cadFeature: CadFeature;
	screwThread: ScrewThread;
	center2: Point2;
}

interface TappingLabel {
	position: Point2;
	text: string;
}

function addSheetTappingLabelsToScene(inputScene: Scene,
	labels: readonly Readonly<TappingLabel>[]) {
	return wsi4.geo.util.addLabelsToScene(inputScene, labels);
}

function tappingLabel(screwThread: ScrewThread, center2d: Point2, text: string): TappingLabel {
	return {
		position: {
			// Position label top right of the core hole
			entries: [
				center2d.entries[0] + screwThread.coreHoleDiameter * 0.5,
				center2d.entries[1] + screwThread.coreHoleDiameter,
			],
		},
		text: text,
	};
}

/**
 * Add zero-based indices to scene for each tapping candidate
 */
export function addSheetTappingNumbersToScene(
	inputScene: Scene,
	tappingCandidates: readonly Readonly<TappingSceneCandidate>[],
	screwThreadsInput?: readonly Readonly<ScrewThread>[],
): Scene {
	const screwThreads = screwThreadsInput ?? getTable(TableType.screwThread);

	const labels = tappingCandidates.map((candidate, index): TappingLabel => {
		const screwThread = screwThreads.find(st => st.identifier === front(candidate.matchingScrewThreads).identifier);
		assert(screwThread !== undefined, "Sheet tapping user data do not match table values.  Expecting valid screwThread.");
		const center = candidate.center2;
		return tappingLabel(screwThread, center, index.toFixed(0));
	});

	return addSheetTappingLabelsToScene(inputScene, labels);
}

/**
 * Add zero-based indices to scene for each tapping candidate
 */
export function addSheetTappingTextToScene(inputScene: Scene, entries: readonly Readonly<TappingSceneSelectionEntry>[]): Scene {
	const screwThreads = getTable(TableType.screwThread);

	const labels = entries.map((candidate): TappingLabel => {
		const screwThread = screwThreads.find(st => st.identifier === candidate.screwThread.identifier);
		assert(screwThread !== undefined, "Sheet tapping user data do not match table values.  Expecting valid screwThread.");
		const center2d = candidate.center2;
		return tappingLabel(screwThread, center2d, screwThread.name);
	});

	return addSheetTappingLabelsToScene(inputScene, labels);
}
