//  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');
      });
    });
  });
