import * as THREE from 'three';
export const DEFAULT_MATERIAL = () => new THREE.MeshPhongMaterial({ 
    color: 0x3335cc, 
    specular: 0x666688,        // Brighter specular for atmospheric highlights
    shininess: 25,             // Allow light reflection
    emissive: 0x0a0a15,       // Subtle glow for base visibility
    emissiveIntensity: 0.15   // Maintain darkness but ensure visibility
});
export const SWITCHED_ON_MATERIAL = () => new THREE.MeshPhongMaterial({ 
    color: 0xfefffe, 
    specular: 0xcccccc,
    shininess: 30,
    emissive: 0x404050,
    emissiveIntensity: 0.3
});
export const SWITCHED_OFF_MATERIAL = () => new THREE.MeshPhongMaterial({ 
    color: 0x222488, 
    specular: 0x444466,
    shininess: 20,
    emissive: 0x0a0a15,
    emissiveIntensity: 0.12
});

export interface Actionable {
    type: string,
    pushed?: boolean
}

export const BUTTON_ACTIONABLE: Actionable = {
    type: "BUTTON",
    pushed: false
}

export interface SingleSideNeighbors {
    up?: Voxel,
    down?: Voxel,
    forward?: Voxel
}

export interface Neighbors {
    west: SingleSideNeighbors,
    east: SingleSideNeighbors,
    north: SingleSideNeighbors,
    south: SingleSideNeighbors
}

export interface Voxel {
    x: number,
    y: number,
    z: number,
    neighs?: Neighbors,
    actionable?: Actionable,
    model?: THREE.Mesh
}

const searchForNeighbors = (
    v: Voxel,
    vxs: Array<Voxel>,
    incx: number,
    incy: number): SingleSideNeighbors => {
    let up = vxs.filter(vt => (vt.x == v.x + incx)
        && (vt.y == v.y + incy)
        && (vt.z == v.z + 1))[0]
    let down = vxs.filter(vt => (vt.x == v.x + incx)
        && (vt.y == v.y + incy)
        && (vt.z == v.z - 1))[0]
    let fwd = vxs.filter(vt => (vt.x == v.x + incx)
        && (vt.y == v.y + incy)
        && (vt.z == v.z))[0]
    return { up: up, down: down, forward: fwd }
}

export const buildNeighborhoodMap = (voxels: Array<Voxel>) => {
    return voxels.map((v) => {
        // Ensure voxel is extensible before adding neighs
        const extensibleVoxel = { ...v }; // Create fresh copy
        let neighs = {
            west: searchForNeighbors(extensibleVoxel, voxels, -1, 0),
            east: searchForNeighbors(extensibleVoxel, voxels, 1, 0),
            north: searchForNeighbors(extensibleVoxel, voxels, 0, 1),
            south: searchForNeighbors(extensibleVoxel, voxels, 0, -1)
        }
        extensibleVoxel.neighs = neighs
        return extensibleVoxel
    })
}

export const buttonVoxelToggle = (voxel: Voxel) => {
    // This function modifies the actual voxel in place, but we need to handle read-only issues
    // Create extensible copies of the actionable object
    if (voxel.actionable) {
        const newPushedState = !voxel.actionable.pushed;
        const extensibleActionable = { ...voxel.actionable, pushed: newPushedState };
        
        if (voxel.model) {
            voxel.model.material = newPushedState ? SWITCHED_ON_MATERIAL() : SWITCHED_OFF_MATERIAL();
        }
        
        // Replace the actionable object (this should work if the main voxel reference is extensible)
        voxel.actionable = extensibleActionable;
    }
}

export const resetVoxels = (voxels: Voxel[]) => {
    return voxels.map((v) => {
        // Create extensible copies to avoid read-only errors
        const extensibleVoxel = { ...v };
        if (extensibleVoxel.actionable) {
            const extensibleActionable = { ...extensibleVoxel.actionable };
            switch (extensibleActionable.type) {
                case ("BUTTON"):
                    if (extensibleVoxel.model) {
                        extensibleVoxel.model.material = SWITCHED_OFF_MATERIAL()
                    }
                    extensibleActionable.pushed = false
                    break
            }
            extensibleVoxel.actionable = extensibleActionable;
        }
        return extensibleVoxel;
    })
}

