//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { importRsaPublicKey, rsaEncrypt, rsaDecrypt, arrayBufferToHexStr } from '@/utils/crypto.ts';

// 创建mock对象
const mockSubtle = {
  importKey: vi.fn(),
  encrypt: vi.fn(),
  decrypt: vi.fn(),
};

const mockCrypto = {
  subtle: mockSubtle,
};

const mockAtob = vi.fn();
const mockBtoa = vi.fn();

describe('加密工具函数', () => {
  beforeEach(() => {
    vi.clearAllMocks();

    // 使用 vi.stubGlobal 来安全的设置全局属性
    vi.stubGlobal('crypto', mockCrypto);
    vi.stubGlobal('window', {
      crypto: mockCrypto,
      atob: mockAtob,
      btoa: mockBtoa,
    });

    vi.stubGlobal(
      'TextEncoder',
      class {
        encode(str) {
          const buffer = new ArrayBuffer(str.length);
          const view = new Uint8Array(buffer);
          for (let i = 0; i < str.length; i++) {
            view[i] = str.charCodeAt(i);
          }
          return view;
        }
      },
    );
  });

  describe('importRsaPublicKey 功能测试', () => {
    it('importRsaPublicKey 应该调用 crypto.subtle.importKey', async () => {
      const mockKey = { type: 'public' };
      mockSubtle.importKey.mockResolvedValue(mockKey);
      mockAtob.mockReturnValue('decode');
      const pem = '-----BEGIN PUBLIC KEY-----\nMock\n-----END PUBLIC KEY-----';
      const result = await importRsaPublicKey(pem);
      expect(mockSubtle.importKey).toHaveBeenCalled();
      expect(result).toBe(mockKey);
    });

    it('rsaEncrypt 应该调用 crypto.subtle.encrypt', async () => {
      const mockEncrypted = new ArrayBuffer(10);
      mockSubtle.encrypt.mockResolvedValue(mockEncrypted);
      const publicKey = {};
      const result = await rsaEncrypt('test', publicKey);
      expect(mockSubtle.encrypt).toHaveBeenCalled();
      expect(result).toBe(mockEncrypted);
    });

    it('rsaDecrypt 应该调用 crypto.subtle.decrypt', async () => {
      const mockDecrypted = new ArrayBuffer(10);
      mockSubtle.decrypt.mockResolvedValue(mockDecrypted);
      const privateKey = {};
      const buffer = new ArrayBuffer(5);
      const result = await rsaDecrypt(buffer, privateKey);
      expect(mockSubtle.decrypt).toHaveBeenCalled();
      expect(result).toBe(mockDecrypted);
    });

    it('应该成功导入RSA公钥', async () => {
      const mockKey = { type: 'public' };
      const pem = `-----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef-----END PUBLIC KEY-----
        `;
      mockAtob.mockReturnValue('base64decoded');

      mockSubtle.importKey.mockResolvedValue(mockKey);
      const result = await importRsaPublicKey(pem, 'SHA-256');
      expect(mockAtob).toHaveBeenCalled();
      expect(mockSubtle.importKey).toHaveBeenCalledWith(
        'spki',
        expect.any(ArrayBuffer),
        {
          name: 'RSA-OAEP',
          hash: 'SHA-256',
        },
        true,
        ['encrypt'],
      );
      expect(result).toBe(mockKey);
    });

    it('应该处理带换行符的PEM格式', async () => {
      const mockKey = { type: 'public' };
      const pem = `-----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef
    -----END PUBLIC KEY-----
    `;
      mockAtob.mockReturnValue('base64decoded');
      mockSubtle.importKey.mockResolvedValue(mockKey);
      await importRsaPublicKey(pem);
      expect(mockAtob).toHaveBeenCalled();
    });
    it('应该使用默认哈希算法', async () => {
      const mockKey = { type: 'public' };
      const pem = `-----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef
    -----END PUBLIC KEY-----`;
      mockAtob.mockReturnValue('base64decoded');
      mockSubtle.importKey.mockResolvedValue(mockKey);
      await importRsaPublicKey(pem);
      expect(mockSubtle.importKey).toHaveBeenCalledWith(
        'spki',
        expect.any(ArrayBuffer),
        {
          name: 'RSA-OAEP',
          hash: 'SHA-1', // 默认值
        },
        true,
        ['encrypt'],
      );
    });
  });
  
  describe('rsaEncrypt', () => {
    it('应该调用crypto.subtle.encrypt', async () => {
      const mockPublicKey = { type: 'public' };
      const mockEncryptedData = new ArrayBuffer(16);
      const testString = 'secret message';
      mockSubtle.encrypt.mockResolvedValue(mockEncryptedData);
      const result = await rsaEncrypt(testString, mockPublicKey);
      expect(mockSubtle.encrypt).toHaveBeenCalledWith(
        {
          name: 'RSA-OAEP',
        },
        mockPublicKey,
        expect.any(ArrayBuffer),
      );
      expect(result).toBe(mockEncryptedData);
    });
    it('应该处理空字符串', async () => {
      const mockPublicKey = { type: 'public' };
      const mockEncryptedData = new ArrayBuffer(0);
      mockSubtle.encrypt.mockResolvedValue(mockEncryptedData);
      const result = await rsaEncrypt('', mockPublicKey);
      expect(result.byteLength).toBe(0);
    });
  });
  
  describe('rsaDecrypt', () => {
    it('应该调用crypto.subtle.decrypt', async () => {
      const mockPrivateKey = { type: 'private' };
      const mockDecryptedData = new ArrayBuffer(10);
      const testBuffer = new ArrayBuffer(16);
      mockSubtle.decrypt.mockResolvedValue(mockDecryptedData);
      const result = await rsaDecrypt(testBuffer, mockPrivateKey);
      expect(mockSubtle.decrypt).toHaveBeenCalledWith(
        {
          name: 'RSA-OAEP',
        },
        mockPrivateKey,
        testBuffer,
      );
      expect(result).toBe(mockDecryptedData);
    });
  });
  
  describe('arrayBufferToHexStr', () => {
    it('应该将ArrayBuffer转换为十六进制字符串', () => {
      const buffer = new ArrayBuffer(3);
      const view = new Uint8Array(buffer);
      view[0] = 0x12;
      view[1] = 0xab;
      view[2] = 0xff;
      const result = arrayBufferToHexStr(buffer);
      expect(result).toBe('12abff');
    });
    it('应该处理单字节值', () => {
      const buffer = new ArrayBuffer(1);
      const view = new Uint8Array(buffer);
      view[0] = 0x0a;
      const result = arrayBufferToHexStr(buffer);
      expect(result).toBe('0a');
    });
    it('应该处理空ArrayBuffer', () => {
      const buffer = new ArrayBuffer(0);
      const result = arrayBufferToHexStr(buffer);
      expect(result).toBe('');
    });
    it('应该对单数字字节补零', () => {
      const buffer = new ArrayBuffer(2);
      const view = new Uint8Array(buffer);
      view[0] = 0x01;
      view[1] = 0x10;
      const result = arrayBufferToHexStr(buffer);
      expect(result).toBe('0110');
    });
    it('应该抛出错误当输入不是ArrayBuffer', () => {
      expect(() => arrayBufferToHexStr(null)).toThrow('Expected input to be an ArrayBuffer');
      expect(() => arrayBufferToHexStr({})).toThrow('Expected input to be an ArrayBuffer');
      expect(() => arrayBufferToHexStr('string')).toThrow('Expected input to be an ArrayBuffer');
    });
  });
  
  describe('基本功能测试', () => {
    it('arrayBufferToHexStr 应该工作', () => {
      const buffer = new ArrayBuffer(2);
      const view = new Uint8Array(buffer);
      view[0] = 0xab;
      view[1] = 0xcd;
      const result = arrayBufferToHexStr(buffer);
      expect(result).toBe('abcd');
    });
  });
});
