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;
}

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

/**
 * Create text items with names of the screw threads to add to a scene
 */
export function createSheetTappingSceneIndexItems(
	tappingCandidates: readonly Readonly<TappingSceneCandidate>[],
	screwThreadsInput?: readonly Readonly<ScrewThread>[],
): SceneTextItem[] {
	const screwThreads = screwThreadsInput ?? getTable(TableType.screwThread);
	return tappingCandidates.map((candidate, index): SceneTextItem => {
		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));
	});
}

/**
 * Create zero-based indices to add to a scene
 */
export function createSheetTappingSceneNameItems(entries: readonly Readonly<TappingSceneSelectionEntry>[]): SceneTextItem[] {
	const screwThreads = getTable(TableType.screwThread);
	return entries.map((candidate): SceneTextItem => {
		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);
	});
}
