"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.methods = void 0;
exports.load = load;
exports.unload = unload;
const ObjectUtil_1 = __importDefault(require("./util/ObjectUtil"));
const FileUtil_1 = __importDefault(require("./util/FileUtil"));
const package_json_1 = __importDefault(require("../package.json"));
const Fs = require('fs');
const Path = require('path');
const EXTENSION_NAME = '🔎';
/** 扩展名对应文件类型 */
const typeMap = {
    '.fire': 'scene',
    '.prefab': 'prefab',
    '.anim': 'animation',
    '.mtl': 'material',
    '.fnt.meta': 'font',
};
/** 类型对应图标 */
const iconMap = {
    'scene': '📺',
    'prefab': '🧸',
    'node': '💾',
    'component': '💿',
    'property': '🎲',
    'asset': '📦',
};
const translate = (key) => `H.${key}`;



/**
 * @en Registration method for the main process of Extension
 * @zh 为扩展的主进程的注册方法
 */
exports.methods = {
    async openDebug() {
		//let rs = await Editor.Message.request('scene', 'query-nodes-by-asset-uuid', '073bed0e-f459-4a3e-833d-3e966a276e86');
        let funs = [];
		for(var key in Editor.Panel){
            funs.push(key);
        }
        // Editor.Dialog.info(JSON.stringify(funs));
        let a = Editor.Utils.UUID.decompressUUID('a5e57jIUsxH948UeGaZ/RhB');
        let b = Editor.Utils.UUID.compressUUID('a5e578c8-52cc-47f7-8f14-786699fd1841');
        Editor.Clipboard.write('text', a + ' , ' + b);  // "7bf9df40-4bc9-4e25-8cb0-9a500f949102");

    },

    /**
     * 打开未使用资源面板
     */
    async openUnusePanel(){
        const res = await Editor.Panel.has('references-finder.unusePanel');
		if(res){
			Editor.Panel.focus('references-finder.unusePanel');
		}else{
			Editor.Panel.open('references-finder.unusePanel');
		}
    },

    /**
     * 查找未使用的资源
     */
    async findUnuse(){

        // 获取所有资源
        let rs = await Editor.Message.request('asset-db', 'query-assets', { pattern: 'db://assets/**' });

        // 过滤掉一些不需要的资源
        const filterImporterList = ["texture", 'typescript', "auto-atlas", "sprite-frame"]
        rs = rs.filter((item)=>!item.isBundle && !item.isDirectory && !filterImporterList.includes(item.importer));

        let types = {};

        rs.forEach(item=>{
            if(!types[item.importer]){
                types[item.importer] = 1;
            }else{
                types[item.importer]++;
            }
        });

        // console.log(types)

        let unuseRs = [];
        for(let i = 0; i < rs.length; i++){
            let item = rs[i];
            // 不需要返回值
            Editor.Message.send('references-finder', 'showProcess', {current:i, total:rs.length, path:item.url});

            let refs = await this.module.methods.findViaUuid(item.uuid);

            let param = await this.module.methods.printResult(refs, item.uuid);

            unuseRs[i] = param;
        }

        Editor.Clipboard.write('text', JSON.stringify(unuseRs));

        rs = unuseRs.map(item=>item.rs);
        
        Editor.Message.send('references-finder', 'showUnuseData', {rs, types});
		
    },

    /**
     * 聚焦并打开到资源
     */
    async foucsAndOpenInAssets(data){
        const {value, uuid} = data;

        Editor.Selection.clear('asset');
        
        Editor.Selection.select('asset', uuid);

        //只有场景和预制体能预览
        if(value.endsWith('.scene') || value.endsWith('.prefab')){
            Editor.Message.request('asset-db', 'open-asset', 'db://' + value);
        }
    },

    /**
     * 点击链接
     */
    async clickLink(data){
		const delay = async (ms)=>{
			return new Promise((cb)=>{
				setTimeout(cb, ms);
			})
		};
		const {isAsset, value, parentKey, uuid, index} = data;
		if(isAsset){
			Editor.Message.request('asset-db', 'open-asset', 'db://' + value);
		}else{

			Editor.Message.request('asset-db', 'open-asset', 'db://' + parentKey);

			await delay(200);

            let searchIds = await Editor.Message.request('scene', 'query-nodes-by-asset-uuid', uuid);

			Editor.Selection.clear('node');
			
			Editor.Selection.select('node', searchIds[index]);
            return;


            /*
			let rs = await Editor.Message.request('scene', 'query-node-tree');

			const getChildByPath = (path, lastNode) => {
				const segments = path.split('/');
				for (let i = 0; i < segments.length; ++i) {
					const segment = segments[i];
					if (segment.length === 0) {
						continue;
					}
					const next = lastNode.children.find((childNode) => childNode.name === segment);
					if (!next) {
						return null;
					}
					lastNode = next;
				}
				return lastNode;
			}
			
			let node = getChildByPath(value, rs) || getChildByPath(value, rs.children[0])
			
			Editor.Selection.clear('node');
			
			Editor.Selection.select('node', node?.uuid);
            */

		}
	},

    /**
     * 刷新 UUID
     */
    async refreshUUID(data){
        const {uuid} = data;
        let rs = await this.module.methods.findViaUuid(uuid);
        let param = await this.module.methods.printResult(rs, uuid);

        this.module.methods.showReferencePanel(param);
    },

    /**
     * 显示引用面板
     */
    async showReferencePanel(param){
        let panelId = 'references-finder.referencePanel';
        const res = await Editor.Panel.has(panelId);
		if(res){
			Editor.Panel.focus(panelId);
            // 不需要返回值
            Editor.Message.send('references-finder', 'showData', param);
		}else{
			Editor.Panel.open(panelId, param);
		}
    },

    

    /**
     * 查找当前选中资源的引用
     */
    async findCurrentSelection() {
        const uuids = Editor.Selection.getSelected('asset');
        if (uuids.length === 0) {
            Editor.Dialog.warn(`[${EXTENSION_NAME}]`, '先选择资源');
            return;
        }
        
        let rs = await this.module.methods.findViaUuid(uuids[0]);
        let param = await this.module.methods.printResult(rs, uuids[0]);

        
        // Editor.Clipboard.write('text', JSON.stringify(param));
        
        this.module.methods.showReferencePanel(param);
    },



    /**
     * 使用 uuid 进行查找
     * @param {string} uuid
     */
    findViaUuid(uuid) {
        return __awaiter(this, void 0, void 0, function* () {
            // 是否为有效 uuid
            if (!Editor.Utils.UUID.isUUID(uuid)) {
                Editor.Dialog.warn(`[${EXTENSION_NAME}]`, 'invalidUuid' + uuid);
                return;
            }
            // 获取资源信息
            const assetInfo = yield Editor.Message.request('asset-db', 'query-asset-info', uuid);
            if (assetInfo) {
                const url = assetInfo.url.replace('db://', '');
                // 暂不查找文件夹
                if (assetInfo.type === 'folder') {
                    Editor.Dialog.warn(`[${EXTENSION_NAME}]`, 'notSupportFolder' + url);
                    return;
                }
                // 处理文件路径 & 打印头部日志
                const urlItems = url.split('/');
                if (!urlItems[urlItems.length - 1].includes('.')) {
                    urlItems.splice(urlItems.length - 1);
                }

                let old = uuid;
                //Editor.Dialog.info(`[${EXTENSION_NAME}]`, 'findAssetRefs' + urlItems.join('/'));
                // 记录子资源 uuid
                const subUuids = assetInfo ? [] : null;
                // 资源类型检查
                if (assetInfo.type === "cc.ImageAsset") {
                    // 纹理子资源
                    uuid = uuid + '@f9941';
                }
                else if (assetInfo.type === 'cc.Script') {
                    // 脚本
                    uuid = Editor.Utils.UUID.compressUUID(uuid);
                    //Editor.Dialog.warn('script,' + old + ',' + uuid);
                    // Editor.Clipboard.write('text', uuid);
                }
                // 查找
                let results = uuid ? yield this.findReferences(uuid) : [];

                if(!results || results.length == 0){
                    //可能是版本原因，脚本压缩参数有的是true，有的需要用false
                    if(assetInfo.type === 'cc.Script'){
                        uuid = Editor.Utils.UUID.compressUUID(uuid, true);
                        results = uuid ? yield this.findReferences(uuid) : [];
                    }
                }
		        //Editor.Clipboard.write('text', JSON.stringify(results));
                
                // Done
                return results;
            }
            else {
                // 不存在的资源，直接查找 uuid
                // Editor.Dialog.warn(`[${EXTENSION_NAME}]`, 'findAssetRefs' + uuid);
                const result = yield this.findReferences(uuid);

                
                return result;
            }
        });
    },

    /**
     * 获取对象中是否包含指定值以及相应属性名
     * @param {object} object 对象
     * @param {any} value 值
     * @returns {{ contains: boolean, property: string }}
     */
    getContainsInfo(object, value) {
        const result = {
            contains: false,
            property: null
        };
        // 搜索
        const search = (target, parentKey) => {
            if (ObjectUtil_1.default.isObject(target)) {
                for (const key in target) {
                    if (target[key] === value) {
                        result.contains = true;
                        result.property = parentKey;
                        return;
                    }
                    search(target[key], key);
                }
            }
            else if (Array.isArray(target)) {
                for (let i = 0, l = target.length; i < l; i++) {
                    search(target[i], parentKey);
                }
            }
        };
        search(object, null);
        // Done
        return result;
    },

    /**
     * 查找节点中的引用
     * @param {object} node 目标节点
     * @param {string} uuid 查找的 uuid
     * @param {object} nodeTree 节点所在的节点树
     * @param {object[]} container 结果容器
     */
    findRefsInNode(node, uuid, nodeTree, container) {
        return __awaiter(this, void 0, void 0, function* () {
            // 检查节点上的组件是否有引用
            const components = node.components;
            if (components && components.length > 0) {
                for (let i = 0, l = components.length; i < l; i++) {
                    const info = this.getContainsInfo(components[i], uuid);
                    if (!info.contains)
                        continue;
                    // 资源类型
                    let type = components[i]['__type__'];
                    // 是否为脚本资源
                    if (Editor.Utils.UUID.isUUID(type)) {
                        const scriptUuid = Editor.Utils.UUID.decompressUUID(type), assetInfo = yield Editor.Message.request('asset-db', 'query-asset-info', scriptUuid);
                        type = Path.basename(assetInfo.url);
                    }
                    // 处理属性名称
                    let property = info.property;
                    if (property) {
                        // Label 组件需要特殊处理
                        if (type === 'cc.Label' && property === '_N$file') {
                            property = 'font';
                        }
                        else {
                            // 去除属性名的前缀
                            if (property.startsWith('_N$')) {
                                property = property.replace('_N$', '');
                            }
                            else if (property[0] === '_') {
                                property = property.substring(1);
                            }
                        }
                    }


                    // 保存结果
                    container.push({
                        node: node.path,
						_node:node,
						uuid:node?.prefab?.fileId,
                        component: type,
                        property: property
                    });
                }
            }
            // 检查预制体是否有引用
            const prefab = node.prefab;
            if (prefab) {
                // 排除预制体自己
                if (uuid !== nodeTree['__uuid__']) {
                    const contains = ObjectUtil_1.default.containsValue(prefab, uuid);
                    if (contains) {
                        // Editor.Clipboard.write('text', JSON.stringify(node));

                        container.push({
                            node: node.path,
                            component:'/',
                            property:'/'
                        });
                    }
                }
            }
            // 遍历子节点
            const children = node.children;
            if (children && children.length > 0) {
                for (let i = 0, l = children.length; i < l; i++) {
                    yield this.findRefsInNode(children[i], uuid, nodeTree, container);
                }
            }
        });
    },
    /**
 * 查找引用
 * @param {string} uuid
 * @returns {object[]}
 */
    findReferences(uuid) {
        return __awaiter(this, void 0, void 0, function* () {
            const results = [];
            /**
             * 文件处理函数
             * @param {string} filePath 文件路径
             * @param {Fs.Stats} stats
             */
            const searchHandler = (filePath, stats) => __awaiter(this, void 0, void 0, function* () {
                const extname = Path.extname(filePath);
                // 场景和预制体资源
                if (extname === '.fire' || extname === '.prefab') {
                    // 将资源数据转为节点树
                    const nodeTree = this.getNodeTree(filePath), children = nodeTree.children, refs = [];
                    // 遍历节点
                    for (let i = 0, l = children.length; i < l; i++) {
                        yield this.findRefsInNode(children[i], uuid, nodeTree, refs);
                    }
                    // 保存当前文件引用结果
                    if (refs.length > 0) {
                        results.push({
                            type: typeMap[extname],
                            fileUrl: yield Editor.Message.request('asset-db', 'query-url', filePath), //Editor.assetdb.fspathToUrl(),
                            refs: refs
                        });
                    }
                }
                // 动画资源
                else if (extname === '.anim') {
                    const data = JSON.parse(Fs.readFileSync(filePath)), curveData = data['curveData'], contains = ObjectUtil_1.default.containsValue(curveData, uuid);
                    if (contains) {
                        results.push({
                            type: typeMap[extname],
                            fileUrl: yield Editor.Message.request('asset-db', 'query-url', filePath)
                        });
                    }
                }
                // 材质和字体资源
                else if (extname === '.mtl' || filePath.indexOf('.fnt.meta') !== -1) {
                    const data = JSON.parse(Fs.readFileSync(filePath)), contains = ObjectUtil_1.default.containsValue(data, uuid);
                    if (contains && !(data['uuid'] === uuid)) {
                        const _extname = (extname === '.mtl') ? '.mtl' : '.fnt.meta';
                        results.push({
                            type: typeMap[_extname],
                            fileUrl: yield Editor.Message.request('asset-db', 'query-url', filePath)
                        });
                    }
                }
            });
            // 遍历资源目录下的文件
            const assetsPath = yield Editor.Message.request('asset-db', 'query-path', 'db://assets/');
            yield FileUtil_1.default.map(assetsPath, searchHandler);
            // Done
            return results;
        });
    },

    /**
     * 获取节点树
     * @param {string} filePath 文件路径
     * @returns {object}
     */
    getNodeTree(filePath) {
        const data = JSON.parse(Fs.readFileSync(filePath));
        let rs = this.convertToNodeTree(data);
        return rs;
    },
    /**
   * 读取节点
   * @param {object} source 元数据
   * @param {number} id 节点 ID
   * @param {object} parent 父容器
   */
    convertNode(source, id, parent) {
        const node = Object.create(null), sourceData = source[id];
        // 基本信息
        node['__id__'] = id;
        node['_name'] = sourceData['_name'];
        node['__type__'] = sourceData['__type__'];
        // 路径
        const parentPath = parent.path || (parent['_name'] || null);
        node.path = (parentPath ? `${parentPath}/` : '') + node['_name'];
        // 组件
        const components = sourceData['_components'];
        if (components && components.length > 0) {
            const _components = node.components = [];
            for (let i = 0, l = components.length; i < l; i++) {
                const sourceComponent = source[components[i]['__id__']];
                _components.push(this.extractValidInfo(sourceComponent));
            }
        }
        // 预制体引用
        const prefab = sourceData['_prefab'];
        if (prefab) {
            const realPrefab = source[prefab['__id__']];
            node.prefab = this.extractValidInfo(realPrefab);
        }
        // 子节点
        const children = sourceData['_children'];
        if (children && children.length > 0) {
            node.children = [];
            for (let i = 0, l = children.length; i < l; i++) {
                const childId = children[i]['__id__'];
                this.convertNode(source, childId, node);
            }
        }
        // 保存数据
        parent.children.push(node);
    },
    /**
    * 提取有效信息（含有 uuid）
    * @param {object} data 元数据
    * @returns {{ __type__: string, _name: string, fileId?: string }}
    */
    extractValidInfo(data) {
        const info = Object.create(null);
        // 记录有用的属性
        const keys = ['__type__', '_name', 'fileId'];
        for (let i = 0, l = keys.length; i < l; i++) {
            const key = keys[i];
            if (data[key]) {
                info[key] = data[key];
            }
        }
        // 记录包含 uuid 的属性
        for (const key in data) {
            if (ObjectUtil_1.default.containsProperty(data[key], '__uuid__')) {
                info[key] = data[key];
            }
        }
        // Done
        return info;
    },
    /**
   * 将资源数据转为节点树
   * @param {object} source 元数据
   * @returns {object}
   */
    convertToNodeTree(source) {
        const nodeTree = Object.create(null), type = source[0]['__type__'];
        // 场景资源
        if (type === 'cc.SceneAsset') {
            const sceneId = source[0]['scene']['__id__'], children = source[sceneId]['_children'];
            nodeTree['__type__'] = 'cc.Scene'; // 类型
            nodeTree['__id__'] = sceneId; // ID
            // 遍历节点
            nodeTree.children = [];
            for (let i = 0, l = children.length; i < l; i++) {
                const nodeId = children[i]['__id__'];
                this.convertNode(source, nodeId, nodeTree);
            }
        }
        // 预制体资源 
        else if (type === 'cc.Prefab') {
            let uuid = undefined;
            for (let i = source.length - 1; i >= 0; i--) {
                if (source[i]['asset']) {
                    uuid = source[i]['asset']['__uuid__'];
                    break;
                }
            }
            nodeTree['__type__'] = 'cc.Prefab'; // 类型
            nodeTree['__uuid__'] = uuid; // uuid
            // 从根节点开始读取
            nodeTree.children = [];
            const rootId = source[0]['data']['__id__'];
            this.convertNode(source, rootId, nodeTree);
        }
        // Done
        return nodeTree;
    },
    async printResult(results, uuid) {
        let path = await Editor.Message.request('asset-db', 'query-url', uuid);
        if (results.length === 0) {
            // Editor.Dialog.warn(`没有找到 ${path}的引用或者不支持查找该类型的资源`);
            // return;
        }

        let url =await Editor.Message.request('asset-db', 'query-path', uuid);

        if(!path){
            path = await Editor.Message.request('asset-db', 'query-url', Editor.Utils.UUID.decompressUUID(uuid));
            url = await Editor.Message.request('asset-db', 'query-path', Editor.Utils.UUID.decompressUUID(uuid));
        }

		const rs = {
			useCount:0,
            uuid:uuid,
            path:path,
            url:url,
			tree:{}
		};
        // 添加引用
        let nodeRefsCount = 0;
        const assetRefs = [];
        let assetRefsCount = 0;
        for (let i = 0, l = results.length; i < l; i++) {
            const result = results[i], type = result.type, url = result.fileUrl.replace('db://', '').replace('.meta', '');
            if (type === 'scene' || type === 'prefab') {
				rs.tree[url] = [];
                const refs = result.refs;
                for (let j = 0, n = refs.length; j < n; j++) {
                    nodeRefsCount++;
                    {
                        const ref = refs[j];
                        
						rs.tree[url].push(ref);
                    }
                }
            }
            else {
                assetRefsCount++;
                assetRefs.push(`　　　·　${iconMap['asset']} [${translate(type)}] ${url}`);
            }
        }
        rs.useCount = nodeRefsCount + assetRefsCount;
        
		const param = {rs};
		

        return param;

		// Editor.Clipboard.write('text', JSON.stringify(rs));

    }
};
/**
 * @en Method Triggered on Extension Startup
 * @zh 扩展启动时触发的方法
 */
function load() { }
/**
 * @en Method triggered when uninstalling the extension
 * @zh 卸载扩展时触发的方法
 */
function unload() { }
