import { Container } from "typescript-ioc";
import { IService, logger } from "mslib";
import { registerService } from "./ServiceRouters";
import * as path from "path";
import * as fs from "fs";

/**
 * 服务扫描器 - 自动扫描 services 和 local-lib 目录下的服务并注册
 */
export class ServiceScanner {

    /**
     * 扫描并注册所有服务
     * @param baseDir 基础目录
     */
    static scanAndRegister(baseDir: string): void {
        const serviceDirs = ['services'];

        logger.info(`[ServiceScanner] Scanning base directory: ${baseDir}`);

        serviceDirs.forEach(dirName => {
            const dirPath = path.join(baseDir, dirName);
            logger.info(`[ServiceScanner] Checking directory: ${dirPath}, exists: ${fs.existsSync(dirPath)}`);
            if (fs.existsSync(dirPath)) {
                ServiceScanner.scanServicesDirectory(dirPath);
            }
        });
    }

    private static scanServicesDirectory(dirPath: string): void {
        const files = fs.readdirSync(dirPath);
        files.forEach(file => {
            const fullPath = path.join(dirPath, file);
            const stat = fs.statSync(fullPath);
            if (stat.isDirectory()) {
                ServiceScanner.scanSubDirectory(fullPath);
            } else {
                ServiceScanner.scanAndRegisterFile(fullPath, file);
            }
        });
    }

    private static scanSubDirectory(dirPath: string): void {
        const files = fs.readdirSync(dirPath);
        files.forEach(file => {
            const fullPath = path.join(dirPath, file);
            const stat = fs.statSync(fullPath);
            if (stat.isDirectory()) {
                ServiceScanner.scanSubDirectory(fullPath);
                return;
            }
            ServiceScanner.scanAndRegisterFile(fullPath, file);
        });
    }

    private static scanAndRegisterFile(filePath: string, fileName: string): void {
        if (!ServiceScanner.isServiceFile(fileName)) {
            return;
        }
        if (!ServiceScanner.shouldRegisterFileName(fileName)) {
            return;
        }
        const sid = ServiceScanner.buildSid(fileName);
        ServiceScanner.loadAndRegister(filePath, sid, fileName);
    }

    private static isServiceFile(fileName: string): boolean {
        const ext = path.extname(fileName);
        return (ext === '.js' || ext === '.ts') && !fileName.endsWith('.d.ts');
    }

    private static shouldRegisterFileName(fileName: string): boolean {
        const ext = path.extname(fileName);
        const name = path.basename(fileName, ext).toLowerCase();
        return !name.startsWith('i')
            && !name.includes('proxy')
            && !name.includes('scanner')
            && !name.includes('router')
            && !name.endsWith('.test')
            && !name.endsWith('declare');
    }

    private static buildSid(fileName: string): string {
        const serviceName = path.basename(fileName, path.extname(fileName)).toLowerCase();
        return serviceName;
    }

    private static loadAndRegister(filePath: string, sid: string, fileName: string): void {
        try {
            delete require.cache[require.resolve(filePath)];
            const module = require(filePath);

            for (const key in module) {
                const exported = module[key];
                if (ServiceScanner.isServiceClass(exported)) {
                    try {
                        const service = Container.get(exported) as IService;
                        registerService(sid, service);
                        logger.info(`[ServiceScanner] Auto registered service: ${sid}, route: /${sid}`);
                    } catch (e) {
                        if (exported.prototype && exported.prototype.doService) {
                            const service = new exported() as IService;
                            registerService(sid, service);
                            logger.info(`[ServiceScanner] Auto registered service (new instance): ${sid}, route: /${sid}`);
                        } else {
                            logger.error(`[ServiceScanner] Failed to register ${sid}: ${e.stack || e.message}`);
                        }
                    }
                    break;
                }
            }
        } catch (e) {
            logger.error(`[ServiceScanner] Failed loading ${fileName} (${filePath}): ${e.stack || e.message}`);
        }
    }

    private static isServiceClass(target: any): boolean {
        if (typeof target !== 'function') return false;
        if (!target.prototype) return false;
        return typeof target.prototype.doService === 'function';
    }
}
