import {
	Costs,
} from "./calc_costs";
import {
	Times,
} from "./calc_times";
import {
	exhaustiveStringTuple,
	isString,
} from "./utils";

/**
 * Version of the graph representation
 *
 * "v0": Use deprecated sheet article semantics
 * 	For sheet nodes there are two cases w.r.t. articles:
 * 	(1) Sheet nodes are part of the associated sheetCutting node's article if
 * 	    the sheetCutting node is the only target of the sheet node.
 * 	(2) Sheet nodes form a dedicated article if two or more sheetCutting nodes
 * 	    are the targets of the sheet node.
 *
 * "v1": Latest version
 * 	Sheet nodes always from a dedicated article regardless of the number of
 * 	target nodes.
 */
export type ErpInterfaceVersion = "v0" | "v1";

export const currentErpInterfaceVersion: ErpInterfaceVersion = "v1";

export function isErpInterfaceVersion(arg: unknown): arg is ErpInterfaceVersion {
	const values = exhaustiveStringTuple<ErpInterfaceVersion>()(
		"v0",
		"v1",
	);
	return isString(arg) && values.some(value => value === arg);
}

/**
 * Represents a node of WorkStepType sheet
 *
 * **Deprecated**;  use [[ProcessRepContentSheet]] instead.
 */
export type SheetWorkStepContent = ProcessRepContentSheet;

/**
 * Represents a node of WorkStepType sheetCutting
 *
 * **Deprecated**;  use [[ProcessRepContentLaserSheetCutting]] instead.
 */
export type SheetCuttingWorkStepContent = ProcessRepContentLaserSheetCutting;

/**
 * Represents a node of WorkStepType sheetBending
 *
 * **Deprecated**;  use [[ProcessRepContentDieBending]] instead.
 */
export type SheetBendingWorkStepContent = ProcessRepContentDieBending;

/**
 * Represents a node of WorkStepType joining
 *
 * **Note** Deprecated.
 */
export interface JoiningWorkStepContent {
}

/**
 * Represents a node of WorkStepType packaging
 *
 * **Note** Deprecated.
 */
export interface PackagingWorkStepContent {
}

/**
 * Represents a node of WorkStepType userDefined
 *
 * **Note** Deprecated.
 */
export interface UserDefinedWorkStepContent {
}

/**
 * Represents a node of WorkStepType userDefinedBase
 *
 * **Note** Deprecated.
 */
export interface UserDefinedBaseWorkStepContent {
}

/**
 * Node representation depending on the node's WorkStepType
 *
 * **Deprecated**;  use [[ProcessRepContent]] instead
 */
export type WorkStepContent =
        SheetWorkStepContent|SheetCuttingWorkStepContent|SheetBendingWorkStepContent|JoiningWorkStepContent|PackagingWorkStepContent|UserDefinedWorkStepContent|UserDefinedBaseWorkStepContent;

/**
 * **Deprecated**;  use [[ProcessRep]] instead
 */
export interface WorkStep {
	type: WorkStepType;
	content: WorkStepContent;
}

/**
 * Represents a node of ProcessType sheet
 */
export interface ProcessRepContentSheet {
	/**
	 * Identifiers of sheets that are part of the nesting; empty if nesting was unsuccessful
	 */
	sheetIds: Array<string>;

	/**
	 * Consumption for the sheets defined in `sheetIds` respectively; empty if nesting was unsuccessful
	 */
	consumptions: Array<number>;

	/**
	 * Thickness of the associated sheets
	 */
	sheetThickness: number;

	/**
	 * X-dimension of the associated sheet
	 *
	 * Undefined in case nesting was unsuccessful.
	 */
	dimX: number | undefined;

	/**
	 * Y-dimension of the associated sheet
	 *
	 * Undefined in case nesting was unsuccessful.
	 */
	dimY: number | undefined;

	/**
	 * If a test report is required
	 *
	 * Note: Property is only provided if the respective setting is enabled.
	 */
	testReportRequired: boolean | undefined;
}

/**
 * Process specific data for ProcessType laserSheetCutting
 */
export interface ProcessRepContentLaserSheetCutting {
	/**
	 * Sum of the lengths of all contours
	 */
	contourLength: number;

	/**
	 * Number of contours
	 */
	contourCount: number;

	/**
	 * Bounding box (2-dim.) of the associated part geometry
	 */
	boundingBox: Box2;

	/**
	 * Thickness of the associated sheet geometry
	 */
	sheetThickness: number;

	/**
	 * Cutting gas identifier
	 *
	 * In case of incomplete data the value can be undefined.
	 */
	cuttingGasId: string | undefined;

	/**
	 * If a test report is required
	 *
	 * Note: Property is only provided if the respective setting is enabled.
	 */
	fixedRotations: number[] | undefined;

	/**
	 * Id of the associated sheet (if any).
	 *
	 * Note:  Property is only provided if there is an associated sheet node with a valid nesting.
	 */
	sheetId: string | undefined;

	/**
	 * Sheet consumption
	 *
	 * Consumption is a floating point value representing the number of total sheets that is consumed.
	 * Consumption entails the part's actual multiplicity.
	 *
	 * Note:  Property is only provided if there is an associated sheet node with a valid nesting.
	 */
	sheetConsumption: number | undefined;
}

export interface GraphRepBendLine {
	/**
	 * Angle of the bend [rad]
	 */
	bendAngle: number;

	/**
	 */
	bendDescriptor: number;

	/**
	 * Segments that forming the bend line.
	 *
	 * The segments are of type `line`.
	 * The segments are colinear.
	 * The segments are not necessarily connected.
	 */
	segments: Segment[];

	/**
	 * Inner radius of the bend as constructed.
	 */
	constructedInnerRadius: number;

	/**
	 * Inner radius of the bend as resulting from the current bend tool selection.
	 */
	resultingInnerRadius: number;

	/**
	 * Legacy property - same as [[constructedInnerRadius]]
	 */
	innerRadius: number;
}

/**
 * Represents a node of ProcessType dieBending
 */
export interface ProcessRepContentDieBending {
	/**
	 * Data for each bend
	 */
	bendLineData: GraphRepBendLine[];

	/**
	 * Thickness of the associated sheet geometry
	 */
	sheetThickness: number;
}

/**
 * Represents a node of ProcessType dieBending
 */
export interface ProcessRepContentAutomaticMechanicalDeburring {
	/**
	 * Net deburring length
	 */
	netLength: number;

	/**
	 * If part should be deburred double sided
	 */
	doubleSided: boolean;
}

/**
 * Represents a node of ProcessType dieBending
 */
export interface ProcessRepContentManualMechanicalDeburring {
	/**
	 * If part should be deburred double sided
	 */
	doubleSided: boolean;
}

/**
 * Process specific data for ProcessType userDefinedThreading
 */
export interface ProcessRepContentUserDefinedThreading {
	numThreads: number;
}

/**
 * Process specific data for ProcessType userDefinedThreading
 */
export interface ProcessRepContentUserDefinedTube {
	tubeId: string;
	dimX: number;
}

/**
 * Process specific data for ProcessType userDefinedCountersinking
 */
export interface ProcessRepContentUserDefinedCountersinking {
	numCountersinks: number;
}

/**
 * A sheet tapping screw thread
 */
export interface SheetTappingDataEntry {
	/**
	 * Center of the thread's core hole
	 *
	 * Coordinates correspond to the associated 2D representation(s)
	 */
	center2: Point2;

	/**
	 * The selected thread
	 */
	screwThread: ScrewThreadUniqueMembers;
}

/**
 * Process specific data for ProcessType sheetTapping
 */
export interface ProcessRepContentSheetTapping {
	/**
	 * [[SheetTappingDataEntry]] for each configured screw thread
	 */
	entries: SheetTappingDataEntry[];
}

/**
 * Process specific data for ProcessType tubeCutting
 */
export interface ProcessRepContentTubeCutting {
	/**
	 * Sum of the lengths of all contours
	 */
	contourLength: number;

	/**
	 * Number of contours
	 */
	contourCount: number;

	/**
	 * Geometry of the tube profile
	 */
	profileGeometry: TubeProfileGeometry;

	/**
	 * Net length of the part in the direction that is orthogonal to the profile cross section plane
	 */
	profileExtrusionLength: number;

	/**
	 * ID of the associated tube (if any).
	 *
	 * Note:  Property is only provided if there is an associated tube node with a valid nesting.
	 */
	tubeId: string | undefined;

	/**
	 * Tube consumption
	 *
	 * Consumption is a floating point value representing the number of total tubes that is consumed.
	 * Consumption entails the part's actual multiplicity.
	 *
	 * Note:  Property is only provided if there is an associated tube node with a valid nesting.
	 */
	tubeConsumption: number | undefined;
}

/**
 * Process specific data for ProcessType tube
 */
export interface ProcessRepContentTube {
	/**
	 * ID of the associated tube (if any).
	 *
	 * Note:  Property is only provided if there is an associated tube node with a valid nesting.
	 */
	tubeId: string | undefined;

	/**
	 * Tube consumption
	 *
	 * Consumption is a floating point value representing the number of total tubes that is consumed.
	 * Consumption entails the associated part's actual multiplicity.
	 *
	 * Note:  Property is only provided if there a valid nesting.
	 */
	consumption: number | undefined;
}

/**
 * Process specific data (if any) or undefined if no specific data is defined for a type
 */
export type ProcessRepContent = undefined
|ProcessRepContentSheet
|ProcessRepContentLaserSheetCutting
|ProcessRepContentDieBending
|ProcessRepContentUserDefinedThreading
|ProcessRepContentUserDefinedCountersinking
|ProcessRepContentAutomaticMechanicalDeburring
|ProcessRepContentManualMechanicalDeburring
|ProcessRepContentUserDefinedTube
|ProcessRepContentSheetTapping
|ProcessRepContentTubeCutting
|ProcessRepContentTube
;

/**
 * Process representation consisting of the process type and specific data (if any)
 */
export interface ProcessRep {
	type: ProcessType;
	content: ProcessRepContent;
}

/**
 * Corresponds to old version of `Costs` used in ts_lib.
 * Required for backwards compatibility.
 */
export interface LegacyCosts {
	/**
	 * Material costs per unit
	 */
	material: number;

	/**
	 * Setup costs
	 */
	setup: number;

	/**
	 * Unit costs per unit
	 */
	unit: number;

	/**
	 * Overall manufacturing price
	 */
	manufacturing: number;

	/**
	 * Overall selling price
	 */
	selling: number;
}

/**
 * Source multiplicity for a vertex
 */
export interface SourceMultiplicity {
	/**
	 * Vertex key of the respective source vertex
	 */
	vertexKey: string;

	/**
	 * Multiplicity of the respective source vertex
	 *
	 * For components (sources) that are part of more than one assembly (targets), source multiplicity can be utilized to get the actual number of occurences for a given assembly.
	 */
	multiplicity: number;
}

/**
 * Common properties for a node
 *
 * Additional WorkStepSpecific properties are defined in interfaces extending this interface.
 */
export interface NodeRepresentation {
	/**
	 * Identifier for a node
	 */
	vertexKey: string;

	/**
	 * Identifiers of source nodes
	 */
	sourceVertexKeys: Array<string>;

	/**
	 * Identifiers of target nodes
	 */
	targetVertexKeys: Array<string>;

	/**
	 * Multiplicity for each source node
	 *
	 * Entries correspond to [[sourceVertexKeys]].
	 * For each source node the respective multiplicity is provided.
	 *
	 * For components that occur in more than one (sub-) assembly the source multiplicity can be different from the node's total multiplicity.
	 * The source node's multiplicity can be considered the total multiplicity of the component (defined in the associated [[NodeRepresentation]].
	 * The source multiplicity represents the number of instances in a certain assembly (defined here).
	 */
	sourceMultiplicities: SourceMultiplicity[];

	/**
	 * Process identifier of the node
	 */
	processId: string;

	/**
	 * User-defined cost center
	 *
	 * Value is user-defined.  There is no guarantee for this value to be
	 * non-empty or valid w.r.t. any external definition.
	 */
	costCenter: string;

	/**
	 * Id submitted with input file
	 *
	 * Note: This id is only present if an input id is explicitly written to `UserData`.
	 */
	importId: string | undefined;

	/**
	 * Manufacturing times for the node (if available)
	 *
	 * Note:  This property and [[userDefinedScalePrices]] are mutually exclusive.
	 */
	times: Times | undefined;

	/**
	 * User defined scale prices
	 *
	 * Note:  Prices correspond to manufacturing costs including surcharges.
	 *
	 * Note:  This property and [[times]] are mutually exclusive.
	 */
	userDefinedScalePrices: UserDefinedScalePrice[];

	/**
	 * Manufacturing and selling costs for the node (if available)
	 */
	costs: LegacyCosts | undefined;

	/**
	 * WorkStepType of the node; defines additional properties
	 *
	 * **Deprecated**;   use [[processRep]] instead.
	 */
	workStep: WorkStep;

	/**
	 * Process specific data; defines additional properties
	 */
	processRep: ProcessRep;

	/**
	 * Mass for the node (if available)
	 */
	mass: number | undefined;

	/**
	 * Comment (empty if there is none)
	 */
	comment: string;
}

/**
 * Scale data entries are computed for each article
 *
 * [[manufacturingCosts]] and [[sellingPrice]] include an approximate material cost share for the article.
 * The material costs are extrapolated based on the article's multiplicity.
 *
 * Note: Scale data is not meaningful for articles consisting of a sheet node only.
 */
export interface ScaleDataEntry {
	/**
	 * The scale value
	 */
	scaleValue: number;

	/**
	 * Scaled [[Costs]]
	 *
	 * For joining-articles this value includes costs of underlying component-articles or sub-joining-articles.
	 *
	 * Note:  Unlike [[LegacyCosts]] the properties `material` and `unit` *do* include the article's underlying multiplicity (i.e. [[scaleValue]]).
	 *
	 * Note:  Value is undefined if user defined scale prices are present for any of the relevant sub-graph's nodes.
	 */
	scaleCosts: Costs | undefined;

	/**
	 * Manufacturing costs
	 *
	 * For component-articles this value includes an approximate material cost share.
	 *
	 * For joining-articles this value includes costs of underlying component-articles or sub-joining-articles.
	 *
	 * Note:  Value is undefined if user defined scale prices are present for any of the relevant sub-graph's nodes.
	 */
	manufacturingCosts: number | undefined;

	/**
	 * Selling price
	 *
	 * For component-articles this value includes an approximate material cost share.
	 *
	 * For joining-articles this value includes costs of underlying component-articles or sub-joining-articles.
	 */
	sellingPrice: number;
}

/**
 * Represents one article
 *
 * An article is a set of nodes.
 *
 * The nodes have the following characteristics:
 * - All nodes have the same multiplicity
 * - All nodes besides the first node have at most one source
 * - All nodes besides the last node have at most one target
 *
 * multiplicity is not meaningful for nodes of WorkStepType sheet and packaging.
 */
export interface ArticleRepresentation {
	/**
	 * Keys of the nodes the article consists of
	 */
	vertexKeys: Array<string>;

	/**
	 * Name of the article
	 *
	 * Note: There is no guarantee for this value to be unique.
	 */
	name: string;

	/**
	 * User-defined part number
	 *
	 * Note: By default this value is unused / empty.
	 */
	externalPartNumber: string;

	/**
	 * User-defined drawing number
	 *
	 * Note: By default this value is unused / empty.
	 */
	externalDrawingNumber: string;

	/**
	 * User-defined revision number
	 *
	 * Note: By default this value is unused / empty.
	 */
	externalRevisionNumber: string;

	/**
	 * Comment for the article
	 */
	comment: string;

	/**
	 * Multiplicity of the article (use with caution)
	 */
	multiplicity: number;

	/**
	 * Material associated with the sheet article (if available)
	 */
	sheetMaterialId: string | undefined;

	/**
	 * Material associated with the sheet article (if available)
	 *
	 * Legacy field; same as [[sheetMaterialId]]
	 */
	globalMaterialId: string | undefined;

	/**
	 * Scale data for the article
	 *
	 * Scale data is computed for component-articles and joining-articles only.
	 *
	 * Scale data is *not* computed for sheet-articles.
	 */
	scaleData: ScaleDataEntry[];
}

/**
 * Maps [[NodeRepresentation]]'s `vertexKey`s to Base64-encoded binary file content
 */
export interface Base64ResourceMap {
	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey`s to Base64-encoded binary file content
	 *
	 * **Note**: In general, there is no guarantee for a `vertexKey` to be part of a [[Base64ResourceMap]].
	 */
	[index: string]: string;
}

/**
 * Maps [[NodeRepresentation]]'s `vertexKey`s to Base64-encoded binary file content
 */
export interface TextResourceMap {
	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey`s to text file content
	 *
	 * **Note**: In general, there is no guarantee for a `vertexKey` to be part of a [[TextResourceMap]].
	 */
	[index: string]: string;
}

/**
 * Maps a set of [[NodeRepresentation]]'s `vertexKey`s to the serialized sub-graph file content
 */
export interface SubGraphResourceEntry {
	/**
	 * List of all [[NodeRepresentation]]'s `vertexKey`s that form the sub-graph
	 */
	vertexKeys: string[];

	/**
	 * Base64 encoded binary data of the sub-graph's WSi4 file content.
	 */
	dataBase64: string;
}

/**
 * Maps [[NodeRepresentation]]'s `vertexKey`s to an array of [[Attachment]]s
 */
export interface AttachmentMap {
	[index: string]: Attachment[];
}

/**
 * Node resources
 *
 * **Note**: Depending on the type of a node various resources are exported.
 *
 * Resource entries are accessible via [[NodeRepresentation]]'s `vertexKey`.
 */
export interface Resources {
	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey` to DXF-file-content (if available)
	 *
	 * **Note**: Depending on a [[NodeRepresentation]]'s underlying `WorkStepType` the DXF file content may vary.
	 *
	 *  For [[NodeRepresentation]]s of type `sheetCutting` the map contains a DXF file defining the sheet cutting contour.
	 *
	 *  For [[NodeRepresentation]]s of type `sheetBending` the map contains a DXF file defining both the sheet contour and bend-lines.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	dxfs: Base64ResourceMap;

	/**
	 * Compressed counterpart to [[dxfs]]
	 *
	 * Each DXF file content is compressed via zlib / Deflate.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	dxfsCompressed: Base64ResourceMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey` to GEO-file-content (if available)
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	geos: Base64ResourceMap;

	/**
	 * Compressed counterpart to [[geos]]
	 *
	 * Each GEO file content is compressed via zlib / Deflate.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	geosCompressed: Base64ResourceMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey` to STEP-file-content (if available)
	 *
	 * **Note**: Each STEP can be considered a sub-set of the input-STEP file.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	inputSteps: Base64ResourceMap;

	/**
	 * Compressed counterpart to [[inputSteps]]
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	inputStepsCompressed: Base64ResourceMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey`  to STEP-file-content (if available)
	 *
	 * **Note**: Each STEP is generated based on computations in WSi4.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	outputSteps: Base64ResourceMap;

	/**
	 * Compressed counterpart to [[outputSteps]]
	 *
	 * Each STEP file content is compressed via zlib / Deflate.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	outputStepsCompressed: Base64ResourceMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey` to attachments (if available)
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	attachments: AttachmentMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey`  to PNG-file-content (if available)
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	pngs: Base64ResourceMap;

	/**
	 * Maps [[NodeRepresentation]]'s `vertexKey` to SVG-file-content (if available)
	 *
	 * **Note**: Depending on a [[NodeRepresentation]]'s underlying `WorkStepType` the SVG file content may vary.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	svgs: Base64ResourceMap;

	/**
	 * Compressed counterpart to [[svgs]]
	 *
	 * Each SVG file content is compressed via zlib / Deflate.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	svgsCompressed: Base64ResourceMap;

	/**
	 * Maps a set of [[NodeRepresentation]]'s `vertexKey`s to WSi4-file-content
	 *
	 * Currently, sub graphs are created for all undirected connected components of the graph.
	 *
	 * Example (1): Two Sub-graphs will be created:
	 * 	- [v0, v1, v2, v3, v4, v5, v6, v7]
	 * 	- [v8, v9]
	 *
	 * ```
	 *    .--> v0 ---> v1 --.
	 *   /                   \
	 * v2 ---> v3 ---> v4 -----> v5 ---> v6
	 *   \                   /
	 *    `--> v7 ----------'
	 *
	 * v8 ---> v9
	 * ```
	 *
	 * Example (2): One sub-graph will be created:
	 * 	- [v0, v1, v2, v3, v4, v5, v6, v7]
	 *
	 * ```
	 *    .--> v0 ---> v1
	 *   /
	 * v2 ---> v3 ---> v4 -----> v5 ---> v6
	 *   \                   /
	 *    `--> v7 ----------'
	 * ```
	 */
	subGraphs: SubGraphResourceEntry[];

	/**
	 * Bend drawings in HTML format
	 *
	 * Each HTML file is self-contained, i.e. no external resources need to be hosted for a file to be viewable via a browser.
	 *
	 * This requires the respective feature to be available for the active license.
	 *
	 * There is no guarantee for a `vertexKey` to be part of this map.
	 */
	bendDrawingHtmls: TextResourceMap;
}

/**
 * Represents the graph
 *
 * **Note**: An article is defined by a sub-set of nodes of the graph and additional data that applies to all nodes of an article.
 */
export interface GraphRepresentation {
	/**
	 * Application name and version
	 */
	creator: string;

	/**
	 * ERP interface version
	 */
	erpInterfaceVersion: ErpInterfaceVersion;

	/**
	 * Name of the project
	 */
	projectName: string;

	/**
	 * Id of the project (if any)
	 *
	 * Value can be set via scripts args
	 */
	projectId: string | undefined;

	/**
	 * Entries for all nodes part of the graph
	 */
	nodes: Array<NodeRepresentation>;

	/**
	 * Entries for all articles part of the graph
	 */
	articles: Array<ArticleRepresentation>;

	/**
	 * Various resources for entries of `nodes`
	 */
	resources: Resources;
}
