import { DataSource, Repository } from 'typeorm';
import { UserEntityMt } from '@d8d/core-module-mt/user-module-mt';
import { FileServiceMt } from '@d8d/core-module-mt/file-module-mt';
import { JWTUtil, redisUtil } from '@d8d/shared-utils';
import axios from 'axios';
import process from 'node:process'

export class MiniAuthService {
  private userRepository: Repository<UserEntityMt>;
  private fileService: FileServiceMt;

  constructor(dataSource: DataSource) {
    this.userRepository = dataSource.getRepository(UserEntityMt);
    this.fileService = new FileServiceMt(dataSource);
  }

  async miniLogin(code: string): Promise<{ token: string; user: UserEntityMt; isNewUser: boolean }> {
    // 1. 通过code获取openid和session_key
    const openidInfo = await this.getOpenIdByCode(code);

    // 2. 查找或创建用户
    let user = await this.userRepository.findOne({
      where: { openid: openidInfo.openid }
    });

    let isNewUser = false;

    if (!user) {
      // 自动注册新用户
      user = await this.createMiniUser(openidInfo);
      isNewUser = true;
    }

    // 3. 保存sessionKey到Redis
    await redisUtil.setSessionKey(user.id, openidInfo.session_key);

    // 4. 生成token
    const token = this.generateToken(user);

    return { token, user, isNewUser };
  }

  async updateUserProfile(userId: number, profile: { nickname?: string; avatarUrl?: string }): Promise<UserEntityMt> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
      relations: ['avatarFile']
    });

    if (!user) throw new Error('用户不存在');

    if (profile.nickname) user.nickname = profile.nickname;

    // 处理头像：如果用户没有头像且提供了小程序头像URL，则下载保存
    if (profile.avatarUrl && !user.avatarFileId) {
      try {
        const avatarFileId = await this.downloadAndSaveAvatar(profile.avatarUrl, userId);
        if (avatarFileId) {
          user.avatarFileId = avatarFileId;
        }
      } catch (error) {
        // 头像下载失败不影响主要功能
        console.error('头像下载失败:', error);
      }
    }

    return await this.userRepository.save(user);
  }

  private async getOpenIdByCode(code: string): Promise<{ openid: string; unionid?: string; session_key: string }> {
    const appId = process.env.WX_MINI_APP_ID;
    const appSecret = process.env.WX_MINI_APP_SECRET;

    if (!appId || !appSecret) {
      throw new Error('微信小程序配置缺失');
    }

    const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${appSecret}&js_code=${code}&grant_type=authorization_code`;

    try {
      const response = await axios.get(url, { timeout: 10000 });

      if (response.data.errcode) {
        throw new Error(`微信API错误: ${response.data.errmsg}`);
      }

      return {
        openid: response.data.openid,
        unionid: response.data.unionid,
        session_key: response.data.session_key
      };
    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error('微信服务器连接失败');
      }
      throw error;
    }
  }

  private async createMiniUser(openidInfo: { openid: string; unionid?: string }): Promise<UserEntityMt> {
    const user = this.userRepository.create({
      username: `wx_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
      password: '', // 小程序用户不需要密码
      openid: openidInfo.openid,
      unionid: openidInfo.unionid,
      nickname: '微信用户',
      registrationSource: 'miniapp',
      isDisabled: 0,
      isDeleted: 0
    });

    return await this.userRepository.save(user);
  }

  private async downloadAndSaveAvatar(avatarUrl: string, userId: number): Promise<number | null> {
    try {
      const result = await this.fileService.downloadAndSaveFromUrl(
        avatarUrl,
        {
          uploadUserId: userId,
          customPath: `avatars/`,
          mimeType: 'image/jpeg'
        },
        { timeout: 10000 }
      );

      return result.file.id;
    } catch (error) {
      console.error('下载保存头像失败:', error);
      return null;
    }
  }

  private generateToken(user: UserEntityMt): string {
    return JWTUtil.generateToken({
      id: user.id,
      username: user.username,
      roles: user.roles,
      openid: user.openid || undefined
    });
  }

  /**
   * 解密小程序加密的手机号
   */
  async decryptPhoneNumber(encryptedData: string, iv: string, sessionKey: string): Promise<string> {

    // 参数验证
    if (!encryptedData || !iv || !sessionKey) {
      throw { code: 400, message: '加密数据或初始向量不能为空' };
    }

    try {
      // 使用Node.js内置crypto模块进行AES-128-CBC解密
      // 微信小程序手机号解密算法：AES-128-CBC，PKCS#7填充
      const crypto = await import('node:crypto');

      // 创建解密器
      const decipher = crypto.createDecipheriv(
        'aes-128-cbc',
        Buffer.from(sessionKey, 'base64'),
        Buffer.from(iv, 'base64')
      );

      // 设置自动PKCS#7填充
      decipher.setAutoPadding(true);

      // 解密数据
      let decrypted = decipher.update(Buffer.from(encryptedData, 'base64'));
      decrypted = Buffer.concat([decrypted, decipher.final()]);

      // 解析解密后的JSON数据
      const decryptedStr = decrypted.toString('utf8');
      const phoneData = JSON.parse(decryptedStr);

      // 验证解密结果
      if (!phoneData.phoneNumber || typeof phoneData.phoneNumber !== 'string') {
        throw new Error('解密数据格式不正确');
      }

      return phoneData.phoneNumber;

    } catch (error) {
      console.error('手机号解密失败:', error);

      // 根据错误类型返回相应的错误信息
      if (error instanceof SyntaxError) {
        throw { code: 400, message: '解密数据格式错误' };
      } else if (error instanceof Error && error.message?.includes('wrong final block length')) {
        throw { code: 400, message: '解密数据长度不正确' };
      } else if (error instanceof Error && error.message?.includes('bad decrypt')) {
        throw { code: 400, message: '解密失败，请检查sessionKey是否正确' };
      } else {
        const errorMessage = error instanceof Error ? error.message : '未知错误';
        throw { code: 400, message: '手机号解密失败: ' + errorMessage };
      }
    }
  }
}