/** @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported. */ /** */

import { Lookup } from './lookup';
import { DeepImmutable, Vector3 } from './babylonjs-import';
import { type PackedIndices, type PackedMeshHash } from '@twinfinity/geometry';
export {
    type TypedArray,
    type PackedPositions,
    type PackedIndices,
    type PackedNormals,
    type PackedMeshHash,
    NormalType,
    type VertexData as BimVertexData
} from '@twinfinity/geometry';

// Make readonly type writable.
export type Mutable<T> = {
    -readonly [P in keyof T]: T[P] extends ReadonlyArray<infer U> ? Mutable<U>[] : Mutable<T[P]>;
};

/**
 * Strip readonly from all properties
 */
export type MutableShallow<T> = { -readonly [P in keyof T]: T[P] };

export interface TypedArrayLike extends ArrayLike<number> {
    // length: number;
    set(array: ArrayLike<number>, offset?: number): void;
    [index: number]: number;
    BYTES_PER_ELEMENT: number;
}

export type SimpleBoundingBox = [number, number, number, number, number, number];

export type SimpleBoundingInfo = {
    corners: [
        [number, number, number],
        [number, number, number],
        [number, number, number],
        [number, number, number],
        [number, number, number],
        [number, number, number],
        [number, number, number],
        [number, number, number]
    ];
    min: [number, number, number];
    max: [number, number, number];
    sizeXYZ: [number, number, number];
    radius: number;
    center: [number, number, number];
};

export interface BimRegion {
    readonly bbox: SimpleBoundingBox;
    readonly isMostPopulated: boolean;
    readonly name: string;
    readonly population: number;
    readonly worldCoordinateSystem: number[];
}

export interface BimIfcPropertiesResponse {
    readonly propertyValues: (string | number | boolean)[];
    readonly propertyNames: string[];
    readonly propertySetNames: string[];
    readonly propertyUnits?: BimPropertyUnit[];
    // The lookup key is the IFC product globalId. The array inside contains indices into the
    // propertySets array.
    readonly products: DeepImmutable<Lookup<number[]>>;
    readonly types: DeepImmutable<Lookup<number[]>>;
    // Each property set has the "hash" property with propertyValue of string. All other property names are actually indexes in the propertyNames array
    // Each property value is a index into the propertyValues array
    readonly propertySets: Array<
        DeepImmutable<{
            s: number; // propertyset name index,
            h: string; // propertset hash
            n: number[]; // property name indexes
            v: number[]; // property value indexes
            u?: number[]; // property unit indexes
        }>
    >;
}

export interface RgbaDTO {
    readonly r: number;
    readonly g: number;
    readonly b: number;
    readonly a: number;
}

export interface BimTypeObjectDTO {
    readonly id: number;
    readonly gid: string;
    readonly c?: number;
    readonly n?: number;
    readonly d?: number;
    readonly t?: number;
    readonly a?: number[];
}

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

export interface BimObjectAttributeDTO {
    readonly n: number;
    readonly v: BimObjectAttributeValue;
}

export interface BimIfcStyleDTO extends RgbaDTO {
    readonly diffuseFactor: number;
    readonly diffuseTransmissionFactor: number;
    // hash representing the properties (except name) of this style.
    // Another style with same hash is therefore the same style (but could have a different name)
    readonly hash: string;
    readonly name: string; // Display name
    readonly reflectionFactor: number;
    readonly specularFactor: number;
    readonly transmissionFactor: number;
    readonly specularExponent?: number;
}

// Describes the mesh
export interface BimProductMeshDescriptor {
    readonly p: number; // primitive count (1 unit is x, y, z)
    readonly i: number; // indice count
    readonly h: string; //hash
    readonly bh: Uint8Array; //hash binary
    readonly obd: number; // Offset in bytes in geom binary
    readonly sbd: number; // Size in bytes of geom data in geom binary
    readonly bbox: SimpleBoundingBox; // bounding box for mesh. Must be transformed to world space, [minX, minY, minZ, maxX, maxY, maxZ]
}

export interface BimProductMeshDTO {
    // References element in BimIfcIndex.meshDescriptors
    readonly mi: number; //mesh index
    // References element in BimIfcIndex.ifcStyles
    readonly si: number; // styleindex
    // Worldspace transform
    readonly wt: number; // worldspace transform
    // the region this mesh belongs to (index of element in BimIfcIndex.regions)
    readonly r: number;
}

export const enum BimPropertiesType {
    quantifier = 0,
    propertyset = 1
}
export type BimPropertySetScalarValueType = string | number | boolean;
export type BimPropertySetValueType = Array<BimPropertySetScalarValueType> | BimPropertySetScalarValueType;

export interface BimPropertyUnit {
    name: string;
    type: string;
}

export type BimPropertyUnitType = Array<BimPropertyUnit> | BimPropertyUnit;

export interface BimTransform {
    // Translation. Undefined means 0
    readonly x: number;
    readonly y: number;
    readonly z: number;
    // Scale. Undefined means 1
    readonly sx: number;
    readonly sy: number;
    readonly sz: number;
    // Quaternion. Undefined means 0
    readonly qx: number;
    readonly qy: number;
    readonly qz: number;
    readonly qw: number; // Undefined means 1
}

export interface BimGeometricFeaturesData {
    readonly meshHash: PackedMeshHash;
    readonly edges: PackedIndices;
}

/** More exact information on what a "hit" operation actually hit on a object. Such as position, normal and distance. */
export interface Intersection {
    /** Generally the position of the intersection on the intersected face. */
    position: Vector3;
    /** Generally the normal of the hit geometry face. There are exceptions when the intersection is approximated, such as when intersecting a point in 3D space. */
    normal: Vector3;
    /** Distance from camera to the intersection. */
    distance: number;
}
