/**
 * Vue插件测试文件
 */

import { VuePlugin, VuePluginOptions, createVuePlugin, useAuth } from './vue';
import { Storage } from '../utils/storage';

// Mock Storage类
class MockStorage {
  private data: Record<string, any> = {};
  
  set(key: string, value: any): void {
    this.data[key] = value;
  }
  
  get(key: string): any {
    return this.data[key];
  }
  
  remove(key: string): void {
    delete this.data[key];
  }
}

// Mock Auth类
class MockAuth {
  init(config: any): void {
    console.log('Auth initialized with config:', config);
  }
  
  login(): void {
    console.log('Login called');
  }
  
  logout(): void {
    console.log('Logout called');
  }
}

// Mock RouterGuard类
class MockRouterGuard {
  createVueGuard() {
    return (to: any, from: any, next: any) => {
      console.log('Route guard called');
      next();
    };
  }
}

// Mock Vue 3 App
class MockVue3App {
  config = {
    globalProperties: {} as Record<string, any>
  };
  
  provide = jest.fn();
  mixin = jest.fn();
  use = jest.fn();
}

// Mock Vue 2 Constructor
class MockVue2Constructor {
  static prototype: Record<string, any> = {};
  static mixin = jest.fn();
  static use = jest.fn();
}

describe('VuePlugin', () => {
  let storage: Storage;
  let vuePlugin: VuePlugin;

  beforeEach(() => {
    storage = new MockStorage() as any;
    vuePlugin = new VuePlugin(storage);
  });

  describe('构造函数', () => {
    test('应该正确初始化', () => {
      expect(vuePlugin).toBeInstanceOf(VuePlugin);
      expect(vuePlugin.getAuth()).toBeDefined();
      expect(vuePlugin.getRouterGuard()).toBeDefined();
      expect(vuePlugin.getStorage()).toBe(storage);
    });

    test('应该在没有存储实例时抛出错误', () => {
      expect(() => new VuePlugin(null as any)).toThrow('Storage instance is required');
    });
  });

  describe('install方法', () => {
    test('应该在没有配置时抛出错误', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = { config: undefined as any };
      
      expect(() => vuePlugin.install(app as any, options)).toThrow('SDK config is required');
    });

    test('应该正确安装Vue 3插件', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any,
        pluginName: 'testLogin'
      };
      
      vuePlugin.install(app as any, options);
      
      // 检查全局属性
      expect(app.config.globalProperties.$testLogin).toBeDefined();
      expect(app.config.globalProperties.$auth).toBeDefined();
      
      // 检查provide调用
      expect(app.provide).toHaveBeenCalledWith('testLogin', expect.anything());
      expect(app.provide).toHaveBeenCalledWith('auth', expect.anything());
    });

    test('应该正确安装Vue 2插件', () => {
      const app = MockVue2Constructor;
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any,
        pluginName: 'testLogin'
      };
      
      vuePlugin.install(app as any, options);
      
      // 检查原型属性
      expect(app.prototype.$testLogin).toBeDefined();
      expect(app.prototype.$auth).toBeDefined();
    });

    test('应该防止重复初始化', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any
      };
      
      // 第一次安装
      vuePlugin.install(app as any, options);
      
      // 第二次安装应该输出警告
      const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
      vuePlugin.install(app as any, options);
      expect(consoleWarnSpy).toHaveBeenCalledWith('Vue plugin is already initialized');
      consoleWarnSpy.mockRestore();
    });

    test('应该支持手动指定Vue版本', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any,
        vueVersion: 'vue2' // 强制使用Vue 2模式
      };
      
      const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
      vuePlugin.install(app as any, options);
      expect(consoleLogSpy).toHaveBeenCalledWith('Unified Login SDK installed successfully (vue2)');
      consoleLogSpy.mockRestore();
    });
  });

  describe('getter方法', () => {
    test('应该正确返回各个实例', () => {
      expect(vuePlugin.getAuth()).toBeDefined();
      expect(vuePlugin.getRouterGuard()).toBeDefined();
      expect(vuePlugin.getStorage()).toBe(storage);
      expect(vuePlugin.getSDK()).toBeDefined();
    });
  });

  describe('辅助函数', () => {
    test('createVuePlugin应该创建插件实例', () => {
      const plugin = createVuePlugin('localStorage', 'test_prefix');
      expect(plugin).toBeInstanceOf(VuePlugin);
      expect(plugin.getStorage()).toBeInstanceOf(Storage);
    });

    test('useAuth应该返回正确的composable对象', () => {
      const composable = useAuth(vuePlugin);
      
      expect(composable.auth).toBe(vuePlugin.getAuth());
      expect(composable.routerGuard).toBe(vuePlugin.getRouterGuard());
      expect(composable.storage).toBe(vuePlugin.getStorage());
      expect(composable.sdk).toBe(vuePlugin.getSDK());
    });
  });

  describe('路由守卫注册', () => {
    test('应该在启用时注册路由守卫', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any,
        autoRegisterGuards: true
      };
      
      vuePlugin.install(app as any, options);
      expect(app.mixin).toHaveBeenCalled();
    });

    test('应该在禁用时不注册路由守卫', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any,
        autoRegisterGuards: false
      };
      
      vuePlugin.install(app as any, options);
      expect(app.mixin).not.toHaveBeenCalled();
    });
  });

  describe('Vue版本检测', () => {
    test('应该正确检测Vue 3', () => {
      const app = new MockVue3App();
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any
      };
      
      const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
      vuePlugin.install(app as any, options);
      expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('(vue3)'));
      consoleLogSpy.mockRestore();
    });

    test('应该正确检测Vue 2', () => {
      const app = MockVue2Constructor;
      const options: VuePluginOptions = {
        config: { clientId: 'test-client' } as any
      };
      
      const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
      vuePlugin.install(app as any, options);
      expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('(vue2)'));
      consoleLogSpy.mockRestore();
    });
  });
});

describe('错误处理', () => {
  test('应该正确处理安装过程中的错误', () => {
    const storage = new MockStorage() as any;
    const plugin = new VuePlugin(storage);
    
    // Mock auth.init 抛出错误
    const mockAuth = plugin.getAuth();
    jest.spyOn(mockAuth, 'init').mockImplementation(() => {
      throw new Error('Init failed');
    });
    
    const app = new MockVue3App();
    const options: VuePluginOptions = {
      config: { clientId: 'test-client' } as any
    };
    
    const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
    
    expect(() => plugin.install(app as any, options)).toThrow('Init failed');
    expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to install Vue plugin:', expect.any(Error));
    
    consoleErrorSpy.mockRestore();
  });
});