import { I18N } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { BaseSysMenuEntity } from '../entity/sys/menu';
import {
  App,
  Config,
  ILogger,
  IMidwayApplication,
  Inject,
  Provide,
  Scope,
  ScopeEnum,
} from '@midwayjs/core';
import * as path from 'path';
import * as fs from 'fs';
import axios from 'axios';
import { DictInfoEntity } from '../../dict/entity/info';
import { DictTypeEntity } from '../../dict/entity/type';
/**
 * 翻译服务
 */
@Provide()
@Scope(ScopeEnum.Singleton)
export class BaseTranslateService {
  @InjectEntityModel(BaseSysMenuEntity)
  baseSysMenuEntity: Repository<BaseSysMenuEntity>;

  @InjectEntityModel(DictInfoEntity)
  dictInfoEntity: Repository<DictInfoEntity>;

  @InjectEntityModel(DictTypeEntity)
  dictTypeEntity: Repository<DictTypeEntity>;

  // 基础路径
  basePath: string;

  @App()
  app: IMidwayApplication;

  @Inject()
  logger: ILogger;

  @Config('cool.i18n')
  config: {
    /** 是否开启 */
    enable: boolean;
    /** 语言 */
    languages: string[];
    /** 翻译服务 */
    serviceUrl?: string;
  };

  menuMap: Record<string, string> = {};

  msgMap: Record<string, string> = {};

  commMap: Record<string, string> = {};

  // 添加字典映射
  dictMap: Record<string, string> = {};

  /**
   * 检查是否存在锁文件
   */
  private checkLockFile(type: 'menu' | 'msg' | 'comm'): boolean {
    const lockFile = path.join(this.basePath, type, '.lock');
    return fs.existsSync(lockFile);
  }

  /**
   * 创建锁文件
   */
  private createLockFile(type: 'menu' | 'msg' | 'comm'): void {
    const lockFile = path.join(this.basePath, type, '.lock');
    fs.writeFileSync(lockFile, new Date().toISOString());
  }

  /**
   * 加载翻译文件到内存
   */
  async loadTranslations() {
    if (!this.config?.enable) {
      return;
    }
    if (!this.basePath) {
      this.basePath = path.join(this.app.getBaseDir(), '..', 'src', 'locales');
    }

    // 清空现有映射
    this.menuMap = {};
    this.msgMap = {};
    this.dictMap = {};
    this.commMap = {};
    // 加载菜单翻译
    await this.loadTypeTranslations('menu', this.menuMap);

    // 加载消息翻译
    await this.loadTypeTranslations('msg', this.msgMap);

    // 加载通用消息翻译
    await this.loadTypeTranslations('comm', this.commMap);

    // 加载字典翻译
    await this.loadDictTranslations();
  }

  /**
   * 加载指定类型的翻译
   * @param type 翻译类型
   * @param map 映射对象
   */
  private async loadTypeTranslations(
    type: 'menu' | 'msg' | 'comm',
    map: Record<string, string>
  ) {
    const dirPath = path.join(this.basePath, type);
    if (fs.existsSync(dirPath)) {
      const files = fs.readdirSync(dirPath);
      for (const file of files) {
        if (file.endsWith('.json')) {
          const language = file.replace('.json', '');
          const content = fs.readFileSync(path.join(dirPath, file), 'utf-8');
          const translations = JSON.parse(content);
          for (const [key, value] of Object.entries(translations)) {
            map[`${language}:${key}`] = value as string;
          }
        }
      }
    }
  }

  /**
   * 加载字典翻译
   */
  private async loadDictTranslations() {
    const dictTypes = ['info', 'type'];

    for (const dictType of dictTypes) {
      const dirPath = path.join(this.basePath, 'dict', dictType);
      if (fs.existsSync(dirPath)) {
        const files = fs.readdirSync(dirPath);
        for (const file of files) {
          if (file.endsWith('.json')) {
            const language = file.replace('.json', '');
            const content = fs.readFileSync(path.join(dirPath, file), 'utf-8');
            const translations = JSON.parse(content);
            for (const [key, value] of Object.entries(translations)) {
              this.dictMap[`${language}:dict:${dictType}:${key}`] =
                value as string;
            }
          }
        }
      }
    }
  }

  /**
   * 更新翻译映射
   * @param type 类型 menu | msg
   * @param language 语言
   */
  async updateTranslationMap(type: 'menu' | 'msg', language: string) {
    const dirPath = path.join(this.basePath, type);
    const file = path.join(dirPath, `${language}.json`);

    if (fs.existsSync(file)) {
      const content = fs.readFileSync(file, 'utf-8');
      const translations = JSON.parse(content);
      const map = type === 'menu' ? this.menuMap : this.msgMap;

      for (const [key, value] of Object.entries(translations)) {
        map[`${language}:${key}`] = value as string;
      }
    }
  }

  /**
   * 翻译
   * @param type 类型 menu | msg | dict
   * @param language 语言
   * @param text 原文
   * @returns 翻译后的文本
   */
  translate(
    type: 'menu' | 'msg' | 'dict:info' | 'dict:type' | 'comm',
    language: string,
    text: string
  ): string {
    // 处理字典翻译
    if (type === 'dict:info' || type === 'dict:type') {
      const key = `${language}:${type}:${text}`;
      return this.dictMap[key] || text.split(':').pop() || text;
    }

    // 处理菜单和消息翻译
    const map = type === 'menu' ? this.menuMap : this.msgMap;
    const key = `${language}:${text}`;
    return map[key] || text;
  }

  /**
   * 检查翻译
   */
  async check() {
    if (this.config?.enable && this.app.getEnv() == 'local') {
      this.basePath = path.join(this.app.getBaseDir(), '..', 'src', 'locales');
      const menuLockExists = this.checkLockFile('menu');
      const msgLockExists = this.checkLockFile('msg');
      const commLockExists = this.checkLockFile('comm');
      const dictLockExists = this.checkDictLockFile();

      if (
        !menuLockExists ||
        !msgLockExists ||
        !dictLockExists ||
        !commLockExists
      ) {
        const tasks = [];
        if (!msgLockExists) {
          tasks.push(this.genBaseMsg());
        }
        if (!menuLockExists) {
          tasks.push(this.genBaseMenu());
        }
        if (!dictLockExists) {
          tasks.push(this.genBaseDict());
        }
        if (!commLockExists) {
          tasks.push(this.genCommMsg());
        }
        // 启动旋转动画
        const spinner = ['|', '/', '-', '\\'];
        let index = 0;
        const interval = setInterval(() => {
          process.stdout.write(`\r${spinner[index++]} i18n translate...`);
          index %= spinner.length;
        }, 200);
        try {
          await Promise.all(tasks);
        } finally {
          clearInterval(interval);
          // 加载翻译文件到内存
          await this.loadTranslations();
          await this.loadDictTranslations();
          process.stdout.write('\r✅ i18n translate success！！！\n');
        }
      } else {
        this.logger.debug('Translation lock files exist, skipping translation');
        // 直接加载翻译文件到内存
        await this.loadTranslations();
        await this.loadDictTranslations();
      }
    }
  }

  /**
   * 检查字典锁文件
   */
  private checkDictLockFile(): boolean {
    const lockFile = path.join(this.basePath, 'dict', '.lock');
    return fs.existsSync(lockFile);
  }

  /**
   * 创建字典锁文件
   */
  private createDictLockFile(): void {
    const lockFile = path.join(this.basePath, 'dict', '.lock');
    fs.writeFileSync(lockFile, new Date().toISOString());
  }

  /**
   * 生成基础字典
   */
  async genBaseDict() {
    try {
      // 检查是否存在锁文件
      if (this.checkDictLockFile()) {
        this.logger.debug('Dictionary lock file exists, skipping translation');
        return;
      }

      const infos = await this.dictInfoEntity.find();
      const types = await this.dictTypeEntity.find();

      // 确保目录存在
      const infoDir = path.join(this.basePath, 'dict', 'info');
      const typeDir = path.join(this.basePath, 'dict', 'type');
      fs.mkdirSync(infoDir, { recursive: true });
      fs.mkdirSync(typeDir, { recursive: true });

      // 生成中文基础文件
      const infoContent = {};
      const typeContent = {};

      for (const info of infos) {
        infoContent[info.name] = info.name;
      }
      for (const type of types) {
        typeContent[type.name] = type.name;
      }

      const infoFile = path.join(infoDir, 'zh-cn.json');
      const typeFile = path.join(typeDir, 'zh-cn.json');

      const infoText = JSON.stringify(infoContent, null, 2);
      const typeText = JSON.stringify(typeContent, null, 2);

      fs.writeFileSync(infoFile, infoText);
      fs.writeFileSync(typeFile, typeText);

      this.logger.debug('Base dictionary files generated successfully');

      // 翻译其他语言
      if (this.config?.enable && this.config.languages) {
        const translatePromises = [];

        for (const language of this.config.languages) {
          if (language !== 'zh-cn') {
            // 翻译 info 字典
            translatePromises.push(
              this.invokeTranslate(infoText, language, infoDir, 'dict')
            );

            // 翻译 type 字典
            translatePromises.push(
              this.invokeTranslate(typeText, language, typeDir, 'dict')
            );
          }
        }

        await Promise.all(translatePromises);
        this.logger.debug('Dictionary translations completed successfully');
      }

      // 创建锁文件
      this.createDictLockFile();

      // 更新翻译映射
      await this.loadDictTranslations();
    } catch (error) {
      this.logger.error('Failed to generate dictionary:', error);
      throw error;
    }
  }

  /**
   * 更新字典翻译映射
   * @param language 语言
   */
  async updateDictTranslationMap(language: string) {
    const infoFile = path.join(
      this.basePath,
      'dict',
      'info',
      `${language}.json`
    );
    const typeFile = path.join(
      this.basePath,
      'dict',
      'type',
      `${language}.json`
    );

    if (fs.existsSync(infoFile)) {
      const content = fs.readFileSync(infoFile, 'utf-8');
      const translations = JSON.parse(content);
      for (const [key, value] of Object.entries(translations)) {
        this.dictMap[`${language}:dict:info:${key}`] = value as string;
      }
    }

    if (fs.existsSync(typeFile)) {
      const content = fs.readFileSync(typeFile, 'utf-8');
      const translations = JSON.parse(content);
      for (const [key, value] of Object.entries(translations)) {
        this.dictMap[`${language}:dict:type:${key}`] = value as string;
      }
    }
  }

  /**
   * 生成基础菜单
   */
  async genBaseMenu() {
    const menus = await this.baseSysMenuEntity.find();
    const file = path.join(this.basePath, 'menu', 'zh-cn.json');
    const content = {};
    for (const menu of menus) {
      content[menu.name] = menu.name;
    }
    // 确保目录存在
    const msgDir = path.dirname(file);
    if (!fs.existsSync(msgDir)) {
      fs.mkdirSync(msgDir, { recursive: true });
    }
    const text = JSON.stringify(content, null, 2);
    fs.writeFileSync(file, text);
    this.logger.debug('base menu generate success');
    const translatePromises = [];
    for (const language of this.config.languages) {
      if (language !== 'zh-cn') {
        translatePromises.push(
          this.invokeTranslate(
            text,
            language,
            path.join(this.basePath, 'menu'),
            'menu'
          )
        );
      }
    }
    await Promise.all(translatePromises);
    this.createLockFile('menu');
  }

  /**
   * 生成基础消息
   */
  async genBaseMsg() {
    const file = path.join(this.basePath, 'msg', 'zh-cn.json');
    const scanPath = path.join(this.app.getBaseDir(), '..', 'src', 'modules');
    const messages = {};

    // 递归扫描目录
    const scanDir = (dir: string) => {
      const files = fs.readdirSync(dir);
      for (const file of files) {
        const fullPath = path.join(dir, file);
        const stat = fs.statSync(fullPath);

        if (stat.isDirectory()) {
          scanDir(fullPath);
        } else if (file.endsWith('.ts')) {
          const content = fs.readFileSync(fullPath, 'utf-8');
          const matches = content.match(
            /throw new CoolCommException\((['"])(.*?)\1\)/g
          );
          if (matches) {
            matches.forEach(match => {
              const message = match.match(/(['"])(.*?)\1/)[2];
              messages[message] = message;
            });
          }
        }
      }
    };

    // 开始扫描
    scanDir(scanPath);

    // 确保目录存在
    const msgDir = path.dirname(file);
    if (!fs.existsSync(msgDir)) {
      fs.mkdirSync(msgDir, { recursive: true });
    }

    // 写入文件
    const text = JSON.stringify(messages, null, 2);
    fs.writeFileSync(file, text);
    this.logger.debug('base msg generate success');

    const translatePromises = [];
    for (const language of this.config.languages) {
      if (language !== 'zh-cn') {
        translatePromises.push(
          this.invokeTranslate(
            text,
            language,
            path.join(this.basePath, 'msg'),
            'msg'
          )
        );
      }
    }
    await Promise.all(translatePromises);
    this.createLockFile('msg');
  }

  /**
   * 生成通用消息
   */
  async genCommMsg() {
    const file = path.join(this.basePath, 'comm', 'zh-cn.json');
    const scanPath = path.join(this.app.getBaseDir(), '..', 'src', 'modules');
    const messages = {};

    // 递归扫描目录
    const scanDir = (dir: string) => {
      const files = fs.readdirSync(dir);
      for (const file of files) {
        const fullPath = path.join(dir, file);
        const stat = fs.statSync(fullPath);

        if (stat.isDirectory()) {
          scanDir(fullPath);
        } else if (file.endsWith('.ts')) {
          const content = fs.readFileSync(fullPath, 'utf-8');
          const matches = content.match(
            /this.translate.comm\((['"])(.*?)\1\)/g
          );
          if (matches) {
            matches.forEach(match => {
              const message = match.match(/(['"])(.*?)\1/)[2];
              messages[message] = message;
            });
          }
        }
      }
    };

    // 开始扫描
    scanDir(scanPath);

    // 确保目录存在
    const msgDir = path.dirname(file);
    if (!fs.existsSync(msgDir)) {
      fs.mkdirSync(msgDir, { recursive: true });
    }

    // 写入文件
    const text = JSON.stringify(messages, null, 2);
    fs.writeFileSync(file, text);
    this.logger.debug('base comm generate success');

    const translatePromises = [];
    for (const language of this.config.languages) {
      if (language !== 'zh-cn') {
        translatePromises.push(
          this.invokeTranslate(
            text,
            language,
            path.join(this.basePath, 'comm'),
            'comm'
          )
        );
      }
    }
    await Promise.all(translatePromises);
    this.createLockFile('comm');
  }

  /**
   * 通用消息翻译
   * @param text 文本
   * @returns 翻译后的文本对象,包含各语言的翻译
   */
  comm(text: string) {
    const translations = {};
    for (const lang of this.config.languages) {
      const langFile = path.join(this.basePath, 'comm', `${lang}.json`);
      if (fs.existsSync(langFile)) {
        const content = JSON.parse(fs.readFileSync(langFile, 'utf-8'));
        translations[lang] = content[text] || text;
      }
    }
    return translations;
  }

  /**
   * 调用翻译
   * @param text 文本
   * @param language 语言
   * @param dirPath 目录
   * @param type 类型
   * @returns
   */
  async invokeTranslate(
    text: string,
    language: string,
    dirPath: string,
    type: 'menu' | 'msg' | 'dict' | 'comm' = 'msg'
  ) {
    this.logger.debug(`${type} ${language} translate start`);
    const response = await axios.post(I18N.DEFAULT_SERVICE_URL, {
      label: 'i18n-node',
      params: {
        text,
        language,
      },
      stream: false,
    });
    const file = path.join(dirPath, `${language}.json`);
    fs.writeFileSync(file, response.data.data.result.data);
    this.logger.debug(`${type} ${language} translate success`);
  }
}
