import { Converter, Converters, ResourceConfig } from ".";
import path from 'path';
import fs from 'fs';
import { keywords_1, keywords_2, keywords_3 } from "./utils";




type MapUniforms = { [name: string]: { type: number, value: any } }
type Material_v1 = {
    shader: string,
    srcshader: string,
    mapUniform: MapUniforms
}

type Material_v2 = {
    shader: string,
    mapUniform: MapUniforms
}

type Material_v3 = {
    extensions: {
        KHR_techniques_webgl: {
            technique: string,
            values: { [k: string]: any; }
        }
        paper: {
            renderQueue: number
        }
    }
}

type MaterialGLTF = {
    asset: {
        version: 2.0,
    },
    materials: Material_v3[],
    extensionsRequired: string[],
    extensionsUsed: string[]
}


/**
 * 将材质文件中的 Vector4 结构从 "(1,1,1,1)" 修改为 [1,1,1,1]
 */
class MaterialConverter implements Converter {
    private resourceConfigJson!: ResourceConfig;
    onStart(rootDir: string) {
        const resourceFile = path.join(rootDir, 'default.res.json');
        const content = fs.readFileSync(resourceFile, 'utf-8');
        this.resourceConfigJson = JSON.parse(content) as ResourceConfig;
    }

    convert(filename: string, v1: Material_v1): Material_v2 {
        // material
        const vector4Regexp = /\([ ]*([0-9.-]+)[ ]*,[ ]*([0-9.-]+)[ ]*,[ ]*([0-9.-]+)[ ]*,[ ]*([0-9.-]+)[ ]*\)/;
        delete v1.srcshader;

        v1.shader = keywords_1[v1.shader] || v1.shader;

        for (let name in v1.mapUniform) {
            const uniform = v1.mapUniform[name];
            if (uniform.type == 9) {
                const v = uniform.value as string | number[];
                if (Array.isArray(v)) {

                }
                else {
                    const result = v.match(vector4Regexp)
                    if (!result) {
                        throw 'error';
                    }
                    result.splice(0, 1)
                    const newValue = result.map(v => parseFloat(v))
                    uniform.value = newValue;
                }
            }
            else if (uniform.type == 3) {
                const v = uniform.value as string | number
                if (typeof v == 'string') {
                    const result = v.match(vector4Regexp)
                    if (result) {
                        uniform.type = 9;
                        result.splice(0, 1);
                        const newValue = result.map(v => parseFloat(v))
                        uniform.value = newValue;
                    }
                }
            }
            else if (uniform.type == 0) {
                //将 name 属性从相对路径修改为 resName
                // const absoluteUrl = this.combinePath(path.dirname(filename) + "/", orginValue);
                const absoluteUrl = path.join(path.dirname(filename), uniform.value).split("\\").join("/");
                const resName = this.getResName(filename, absoluteUrl);
                uniform.value = resName;
            }
        }
        return v1
    }
    private getResName(filename: string, url: string) {
        const result = this.resourceConfigJson.resources.find((item) => item.url == url);
        if (result) {
            return result.name
        }
        else {
            throw new Error(`missing ${url} in ${filename}`)
        }
    }
    onFinish(): void {

    }
}

/**
 * TODO
 */
class Material2To3Converter implements Converter {
    onStart(rootDir: string) {
    }

    convert(filename: string, v2: Material_v2): MaterialGLTF {
        const gltfAsset: MaterialGLTF = { asset: { version: 2.0 }, materials: [] } as any;
        const v3: Material_v3 = { extensions: { KHR_techniques_webgl: {}, paper: { renderQueue: -1 } } } as any;
        const KHR_techniques_webgl = v3.extensions.KHR_techniques_webgl;
        const orginShader = v2.shader in keywords_2 ? keywords_2[v2.shader] : v2.shader;
        const shaderPath = orginShader.replace(".json", ".gltf");
        KHR_techniques_webgl.technique = shaderPath;
        KHR_techniques_webgl.values = {};

        for (const key in v2.mapUniform) {
            KHR_techniques_webgl.values[key] = v2.mapUniform[key].value;
        }

        gltfAsset.materials.push(v3);

        gltfAsset.extensionsRequired = ["KHR_techniques_webgl", "paper"];
        gltfAsset.extensionsUsed = ["KHR_techniques_webgl", "paper"];

        return gltfAsset;
    }

    onFinish() {

    }
}

//buildin->builtin
class Material3To4Converter implements Converter {
    onStart(rootDir: string) {
    }

    convert(filename: string, v2: MaterialGLTF): MaterialGLTF {
        for (const mat of v2.materials) {
            const KHR_techniques_webgl = mat.extensions.KHR_techniques_webgl;
            if (!mat.extensions.paper) {
                mat.extensions.paper = { renderQueue: 2000 };
            }
            if (KHR_techniques_webgl.technique.indexOf("diffuse") >= 0) {
                KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace("diffuse", "meshbasic");
            }
            else if (KHR_techniques_webgl.technique.indexOf("transparent_alphaCut") >= 0) {
                KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace("transparent_alphaCut", "transparent");
            }
            else if (KHR_techniques_webgl.technique.indexOf("transparent_tintColor") >= 0) {
                KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace("transparent_tintColor", "transparent");
            }
            else if (KHR_techniques_webgl.technique.indexOf("particle_blend1") >= 0) {
                KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace("particle_blend1", "particle_blend");
            }
            //
            //
            KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace("buildin", "builtin");
            KHR_techniques_webgl.technique = KHR_techniques_webgl.technique.replace(".gltf", ".json");
            const shaderName = KHR_techniques_webgl.technique;
            if (shaderName.indexOf("particle") >= 0) {
                if (shaderName.indexOf("particle_") >= 0) {
                    mat.extensions.paper.renderQueue = 3000;
                }
                else {
                    mat.extensions.paper.renderQueue = 2000;
                }
            }
            else if (shaderName.indexOf("transparent") >= 0) {
                if (shaderName.indexOf("alphaCut") >= 0) {
                    mat.extensions.paper.renderQueue = 2450;
                }
                else {
                    mat.extensions.paper.renderQueue = 3000;
                }
            }
            else {
                mat.extensions.paper.renderQueue = 2000;
            }

            for (var uniformKey in KHR_techniques_webgl.values) {
                if (uniformKey in keywords_3) {
                    let uniformValue = KHR_techniques_webgl.values[uniformKey];
                    if (uniformKey === "_MainColor" || uniformKey === "_Color" || uniformKey === "_TintColor") {
                        //Three.js中把 rgb和a分开处理
                        KHR_techniques_webgl.values["opacity"] = uniformValue[3];
                        uniformValue = (uniformValue as []).slice(0, 3);
                    }
                    else if (uniformKey === "_MainTex_ST") {
                        uniformValue = [uniformValue[0], 0, 0, 0, uniformValue[1], 0, uniformValue[2], uniformValue[3], 1];
                    }
                    KHR_techniques_webgl.values[keywords_3[uniformKey]] = uniformValue;
                    delete KHR_techniques_webgl.values[uniformKey];
                }
                else {
                    console.warn("不识别的key值:" + uniformKey + " file:" + filename);
                }
            }

            //
            if (KHR_techniques_webgl.values["map"]) {
                if (KHR_techniques_webgl.values["map"].indexOf(".imgdesc.json") > 0) {
                    KHR_techniques_webgl.values["map"] = KHR_techniques_webgl.values["map"].replace(".imgdesc.json", ".image.json");
                }
            }
        }
        return v2;
    }

    onFinish() {

    }
}


export const materialConverters: Converters = {

    matcher: "**/**/*.mat.json",

    converters: [new MaterialConverter, new Material2To3Converter, new Material3To4Converter]
}

