import { _decorator, Component, Node, DirectionalLight, director, Color, Vec3, Enum, CCFloat, renderer, TextureCube, assetManager, MeshRenderer, CCBoolean, CCInteger } from 'cc';
import { EDITOR } from 'cc/env';
const { ccclass, property, executeInEditMode } = _decorator;

enum presetEnvs {
    none,
    cool,
    warm,
}
enum envSettings {
    OFF,
    ON,
}
const preConfigs = [
    {
        skyIllu: 22000,
        lightIllu: 100000,
        lightDirection: new Vec3(-120, -120, 0),
        lightColor: new Color(255, 255, 255),
        skyColor: new Color(101, 121, 160),
        groundColor: new Color(63, 55, 40),
    },
    {
        skyIllu: 20000,
        lightIllu: 120000,
        lightColor: new Color(255, 255, 255),
        lightDirection: new Vec3(-150, -148, 0),
        skyColor: new Color(77, 236, 89),
        groundColor: new Color(116, 116, 116),
    },


]
const v1 = new Vec3();

@ccclass('QuickEnv')
@executeInEditMode(true)
export class QuickEnv extends Component {
    @property({ group: "shadow" })
    get shadow() {
        return director.getScene().globals.shadows.enabled;
    }
    set shadow(v: boolean) {
        director.getScene().globals.shadows.enabled = v;

    }

    @property({
        type: Enum(renderer.scene.ShadowType), group: "shadow", visible() {
            return this.shadow;
        },
    })
    get shadowType() {
        return director.getScene().globals.shadows.type;
    }
    set shadowType(v: number) {
        director.getScene().globals.shadows.type = v;
        if (v == renderer.scene.ShadowType.ShadowMap) {
            this.directLight.shadowEnabled = true;
        }
    }
    @property({
        group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get shadowCSM() {
        return this.directLight.enableCSM;
    }
    set shadowCSM(v: boolean) {
        this.directLight.enableCSM = v;
    }
    @property({
        type: Enum(renderer.scene.ShadowSize), group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get ShadowSize() {
        return director.getScene().globals.shadows.shadowMapSize;
    }
    set ShadowSize(v: number) {
        director.getScene().globals.shadows.shadowMapSize = v;
    }
    @property({
        type: CCFloat, min: 1, max: 200, slide: true,
        group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get shadwoDistance() {
        return this.directLight.shadowDistance;
    }
    set shadwoDistance(v: number) {
        this.directLight.shadowDistance = v;
    }
    @property({
        type: CCFloat, min: 0, max: 1, slide: true, step: 0.01,
        group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get shadowSaturation() {
        return this.directLight.shadowSaturation;
    }
    set shadowSaturation(v: number) {
        this.directLight.shadowSaturation = v;
    }
    @property({
        type: Enum(renderer.scene.PCFType), group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get shadowPcf() {
        return this.directLight.shadowPcf;
    }
    set shadowPcf(v: number) {
        this.directLight.shadowPcf = v;
    }

    @property({
        group: "shadow", visible() {
            return this.shadow && this.shadowType == renderer.scene.ShadowType.ShadowMap;
        },
    })
    get shadowBias() {
        return this.directLight.shadowBias;
    }
    set shadowBias(v: number) {
        this.directLight.shadowBias = v;
    }



    @property({ group: "skybox" })
    get skybox() {
        return director.getScene().globals.skybox.enabled;
    }
    set skybox(v: boolean) {
        director.getScene().globals.skybox.enabled = v
    }

    @property({
        group: "skybox", visible() {
            return this.skybox;
        },
    })
    get skyboxTexture() {
        return director.getScene().globals.skybox.envmap;
    }
    set skyboxTexture(v: TextureCube) {
        director.getScene().globals.skybox.envmap = v
    }

    @property({
        type: Enum(renderer.scene.EnvironmentLightingType),
        group: "skybox", visible() {
            return this.skybox;
        },
    })
    get skyBoxType() {
        return director.getScene().globals.skybox.envLightingType;
    }
    set skyBoxType(v: number) {
        director.getScene().globals.skybox.envLightingType = v
    }

    @property({
        min: 0, max: 360, slide: true,
        group: "skybox", visible() {
            return this.skybox;
        },
    })
    get skyboxRotation() {
        return director.getScene().globals.skybox.rotationAngle;
    }
    set skyboxRotation(v: number) {
        director.getScene().globals.skybox.rotationAngle = v
    }

    @property({ group: "fog" })
    get fog() {
        return director.getScene().globals.fog.enabled;
    }
    set fog(v: boolean) {
        director.getScene().globals.fog.enabled = v
    }

    @property({
        type: Enum(renderer.scene.FogType),
        group: "fog", visible() {
            return this.fog;
        },
    })
    get fogType() {
        return director.getScene().globals.fog.type;
    }
    set fogType(v: number) {
        director.getScene().globals.fog.type = v
    }

    // @property({
    //     type: CCInteger,
    //     group: "model",
    //     readonly: true
    // })
    // get MeshesAmount() {
    //     const meshes = director.getScene().getComponentsInChildren(MeshRenderer);

    //     let L = meshes.length;

    //     // if (EDITOR) {
    //     //     /* gizmos meshes in editor */
    //     //     L -= 56;
    //     // }
    //     return L;
    // }
    // set MeshesAmount(v: number) { }

    @property({
        type: Enum(envSettings),
        group: "model",
    })
    get ModelsCastShadows() {
        return this.castShadows;
    }
    set ModelsCastShadows(v: number) {
        this.castShadows = v
        const meshes = director.getScene().getComponentsInChildren(MeshRenderer);
        const L = meshes.length;
        if (L > 0) {
            for (var i = 0; i < L; i++) {
                meshes[i].shadowCastingMode = v;
            }
        }
    }

    @property({ visible: false })
    castShadows: number = envSettings.OFF;

    @property({
        type: Enum(envSettings),
        group: "model",
    })
    get ModelsReceiveShadows() {
        return this.receive;
    }
    set ModelsReceiveShadows(v: number) {
        this.receive = v
        const meshes = director.getScene().getComponentsInChildren(MeshRenderer);
        const L = meshes.length;
        if (L > 0) {
            for (var i = 0; i < L; i++) {
                meshes[i].receiveShadow = v;
            }
        }
    }
    @property({ visible: false })
    receive: number = envSettings.OFF;

    @property({ type: CCFloat, min: 0, max: 160000, slide: true, step: 10 })
    get skyIllu() {
        return director.getScene().globals.ambient.skyIllum;
    }
    set skyIllu(v: number) {
        director.getScene().globals.ambient.skyIllum = v;
    }

    @property
    get skyColor() {
        return director.getScene().globals.ambient.skyLightingColor;
    }
    set skyColor(v: Color) {
        director.getScene().globals.ambient.skyLightingColor = v;
    }

    @property
    get groundColor() {
        return director.getScene().globals.ambient.groundLightingColor;
    }
    set groundColor(v: Color) {
        director.getScene().globals.ambient.groundLightingColor = v;
    }

    @property
    get directLightColor() {

        return this.directLight.color;
    }
    set directLightColor(v: Color) {

        this.directLight.color = v;
    }

    @property({ type: CCFloat, min: 0, max: 160000, slide: true, step: 10 })
    get directLightIllu() {

        return this.directLight.illuminance;
    }
    set directLightIllu(v: number) {

        this.directLight.illuminance = v;
    }
    @property
    get directLightDirection() {

        return this.light.eulerAngles;
    }
    set directLightDirection(v: Vec3) {

        this.light.eulerAngles = v;
    }
    @property({ type: CCFloat, min: -360, max: 360, slide: true })
    get directLightDirectX() {

        return this.light.eulerAngles.x;
    }
    set directLightDirectX(v: number) {

        v1.set(this.light.eulerAngles);
        v1.x = v;
        this.light.eulerAngles = v1;
    }
    @property({ type: CCFloat, min: -360, max: 360, slide: true })
    get directLightDirectY() {

        return this.light.eulerAngles.y;
    }
    set directLightDirectY(v: number) {

        v1.set(this.light.eulerAngles);
        v1.y = v;
        this.light.eulerAngles = v1;
    }
    @property({ type: CCFloat, min: -360, max: 360, slide: true })
    get directLightDirectZ() {
        if (!this.directLight) {
            this.directLight = director.getScene().getComponentInChildren(DirectionalLight)
        }

        return this.light.eulerAngles.z;
    }
    set directLightDirectZ(v: number) {
        v1.set(this.light.eulerAngles);
        v1.z = v;
        this.light.eulerAngles = v1;
    }


    get light(): Node {
        if (!this.directLight) {
            this.directLight = director.getScene().getComponentInChildren(DirectionalLight);
        }
        return this.directLight.node;
    }


    @property({ type: (Enum(presetEnvs)) })
    get preEnvs() {
        return this.currentSet;
    }
    set preEnvs(v) {
        this.currentSet = v;
        if (v > 0) {
            const config = preConfigs[v - 1];
            this.directLightDirection = config.lightDirection;
            this.directLightColor = config.lightColor;
            this.directLightIllu = config.lightIllu;
            this.skyColor = config.skyColor;
            this.skyIllu = config.skyIllu;
            this.groundColor = config.groundColor;

        }
    }


    @property({ type: (Enum(presetEnvs)), visible: false })
    currentSet: presetEnvs = presetEnvs.none;

    private directLight: DirectionalLight = null;


    onEnable() {
        if (EDITOR) {
            const scene = director.getScene();
            scene.on(Node.EventType.CHILD_ADDED, () => {
                const meshes = scene.getComponentsInChildren(MeshRenderer);
                const L = meshes.length;
                if (L > 0) {
                    for (var i = 0; i < L; i++) {
                        meshes[i].receiveShadow = this.receive;
                    }
                    for (var i = 0; i < L; i++) {
                        meshes[i].shadowCastingMode = this.castShadows;
                    }
                }


            }, this)
            this.directLight = scene.getComponentInChildren(DirectionalLight);

        }

    }


}

