/**
 * 测试环境设置
 * 遵循前端开发规范的测试配置
 */

import { vi, beforeAll, afterAll, expect } from 'vitest';
import '@testing-library/jest-dom';

// Mock Tauri API
global.window = Object.create(window);
(global.window as any).__TAURI__ = {
  invoke: vi.fn(),
  event: {
    listen: vi.fn(),
    emit: vi.fn(),
  },
  path: {
    join: vi.fn(),
    dirname: vi.fn(),
  },
  fs: {
    readTextFile: vi.fn(),
    writeTextFile: vi.fn(),
    exists: vi.fn(),
  },
};

// Mock IntersectionObserver
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// Mock ResizeObserver
global.ResizeObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// Mock matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(), // deprecated
    removeListener: vi.fn(), // deprecated
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
});

// Mock scrollTo
Object.defineProperty(window, 'scrollTo', {
  writable: true,
  value: vi.fn(),
});

// Mock localStorage
const localStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
};
Object.defineProperty(window, 'localStorage', {
  value: localStorageMock,
});

// Mock sessionStorage
const sessionStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
};
Object.defineProperty(window, 'sessionStorage', {
  value: sessionStorageMock,
});

// Mock URL.createObjectURL
Object.defineProperty(URL, 'createObjectURL', {
  writable: true,
  value: vi.fn(() => 'mocked-url'),
});

// Mock URL.revokeObjectURL
Object.defineProperty(URL, 'revokeObjectURL', {
  writable: true,
  value: vi.fn(),
});

// Mock console methods for cleaner test output
const originalError = console.error;
beforeAll(() => {
  console.error = (...args: any[]) => {
    if (
      typeof args[0] === 'string' &&
      args[0].includes('Warning: ReactDOM.render is deprecated')
    ) {
      return;
    }
    originalError.call(console, ...args);
  };
});

afterAll(() => {
  console.error = originalError;
});

// Global test utilities
export const createMockInvoke = (responses: Record<string, any>) => {
  return vi.fn().mockImplementation((command: string, args?: any) => {
    if (responses[command]) {
      if (typeof responses[command] === 'function') {
        return Promise.resolve(responses[command](args));
      }
      return Promise.resolve(responses[command]);
    }
    return Promise.reject(new Error(`Mock not found for command: ${command}`));
  });
};

export const createMockTemplate = (overrides = {}) => ({
  id: 'template-1',
  name: '测试模板',
  description: '这是一个测试模板',
  file_path: '/path/to/template',
  import_status: 'Completed',
  project_id: null,
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
  ...overrides,
});

export const createMockModel = (overrides = {}) => ({
  id: 'model-1',
  name: '测试模特',
  stage_name: '艺名',
  description: '这是一个测试模特',
  avatar_url: null,
  tags: ['标签1', '标签2'],
  is_active: true,
  created_at: new Date('2024-01-01T00:00:00Z'),
  updated_at: new Date('2024-01-01T00:00:00Z'),
  ...overrides,
});

export const createMockMaterial = (overrides = {}) => ({
  id: 'material-1',
  project_id: 'project-1',
  name: '测试素材.mp4',
  original_path: '/path/to/material.mp4',
  file_size: 1024000,
  md5_hash: 'abcd1234',
  material_type: 'Video',
  processing_status: 'Completed',
  metadata: {
    Video: {
      duration: 120,
      width: 1920,
      height: 1080,
      fps: 30,
      bitrate: 5000000,
      codec: 'h264',
      format: 'mp4',
      has_audio: true,
    },
  },
  scene_detection: null,
  segments: [],
  model_id: null,
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
  processed_at: '2024-01-01T00:00:00Z',
  error_message: null,
  ...overrides,
});

export const createMockProjectTemplateBinding = (overrides = {}) => ({
  id: 'binding-1',
  project_id: 'project-1',
  template_id: 'template-1',
  binding_name: '测试绑定',
  description: '这是一个测试绑定',
  priority: 0,
  is_active: true,
  binding_type: 'Primary',
  binding_status: 'Active',
  metadata: null,
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
  ...overrides,
});

export const createMockProject = (overrides = {}) => ({
  id: 'project-1',
  name: '测试项目',
  path: '/path/to/project',
  description: '这是一个测试项目',
  created_at: '2024-01-01T00:00:00Z',
  updated_at: '2024-01-01T00:00:00Z',
  ...overrides,
});

// Test data generators
export const generateTestData = {
  templates: (count: number) =>
    Array.from({ length: count }, (_, i) =>
      createMockTemplate({
        id: `template-${i + 1}`,
        name: `模板${i + 1}`,
      })
    ),
  
  models: (count: number) =>
    Array.from({ length: count }, (_, i) =>
      createMockModel({
        id: `model-${i + 1}`,
        name: `模特${i + 1}`,
        stage_name: `艺名${i + 1}`,
      })
    ),
  
  materials: (count: number, projectId = 'project-1') =>
    Array.from({ length: count }, (_, i) =>
      createMockMaterial({
        id: `material-${i + 1}`,
        project_id: projectId,
        name: `素材${i + 1}.mp4`,
      })
    ),
  
  bindings: (count: number, projectId = 'project-1') =>
    Array.from({ length: count }, (_, i) =>
      createMockProjectTemplateBinding({
        id: `binding-${i + 1}`,
        project_id: projectId,
        template_id: `template-${i + 1}`,
        binding_name: `绑定${i + 1}`,
        priority: i,
      })
    ),
};

// Custom matchers
expect.extend({
  toBeValidUUID(received: string) {
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
    const pass = uuidRegex.test(received);
    
    if (pass) {
      return {
        message: () => `expected ${received} not to be a valid UUID`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be a valid UUID`,
        pass: false,
      };
    }
  },
});

declare global {
  namespace jest {
    interface Matchers<R> {
      toBeValidUUID(): R;
    }
  }
}
