import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import Dashboard from '../pages/Dashboard';
import { getDevices, getLatestData } from '../services/api';

// Mock the API services
jest.mock('../services/api');
const mockGetDevices = getDevices as jest.MockedFunction<typeof getDevices>;
const mockGetLatestData = getLatestData as jest.MockedFunction<typeof getLatestData>;

// Mock the hooks
jest.mock('../hooks/useDevices');
jest.mock('../hooks/useSensorData');

const mockUseDevices = require('../hooks/useDevices').useDevices;
const mockUseSensorData = require('../hooks/useSensorData').useSensorData;

const renderWithRouter = (component: React.ReactElement) => {
  return render(
    <BrowserRouter>
      {component}
    </BrowserRouter>
  );
};

describe('Dashboard Integration', () => {
  const mockDevices = [
    {
      id: 1,
      device_id: 'sensor-001',
      name: '테스트 센서',
      status: 'active',
      last_seen: '2025-08-01T10:00:00Z'
    }
  ];

  const mockSensorData = [
    {
      device_id: 'sensor-001',
      temperature: 25.5,
      humidity: 60.0,
      pm10: 15.2,
      pm25: 8.1,
      pressure: 1013.25,
      illumination: 500,
      tvoc: 120,
      co2: 450,
      o2: 20.9,
      co: 0.5,
      recorded_time: '2025-08-01T10:00:00Z'
    }
  ];

  beforeEach(() => {
    jest.clearAllMocks();
    
    // Mock useDevices hook
    mockUseDevices.mockReturnValue({
      devices: mockDevices,
      loading: false,
      error: null,
      refetch: jest.fn()
    });

    // Mock useSensorData hook
    mockUseSensorData.mockReturnValue({
      latestData: mockSensorData,
      loading: false,
      error: null,
      refetch: jest.fn()
    });
  });

  it('should render dashboard with sensor data', async () => {
    renderWithRouter(<Dashboard />);

    // Check if main title is rendered
    expect(screen.getByText('센서 대시보드')).toBeInTheDocument();

    // Check if sensor cards are rendered
    await waitFor(() => {
      expect(screen.getByText('현재 온도')).toBeInTheDocument();
      expect(screen.getByText('현재 습도')).toBeInTheDocument();
      expect(screen.getByText('PM10')).toBeInTheDocument();
      expect(screen.getByText('PM2.5')).toBeInTheDocument();
    });

    // Check if sensor values are displayed correctly
    expect(screen.getByText('25.5°C')).toBeInTheDocument();
    expect(screen.getByText('60.0%')).toBeInTheDocument();
    expect(screen.getByText('15.2μg/m³')).toBeInTheDocument();
    expect(screen.getByText('8.1μg/m³')).toBeInTheDocument();
  });

  it('should display loading state', () => {
    mockUseDevices.mockReturnValue({
      devices: [],
      loading: true,
      error: null,
      refetch: jest.fn()
    });

    mockUseSensorData.mockReturnValue({
      latestData: [],
      loading: true,
      error: null,
      refetch: jest.fn()
    });

    renderWithRouter(<Dashboard />);

    expect(screen.getByText('데이터를 불러오는 중...')).toBeInTheDocument();
  });

  it('should display error state', () => {
    mockUseDevices.mockReturnValue({
      devices: [],
      loading: false,
      error: '디바이스 목록을 불러올 수 없습니다.',
      refetch: jest.fn()
    });

    renderWithRouter(<Dashboard />);

    expect(screen.getByText('오류가 발생했습니다')).toBeInTheDocument();
    expect(screen.getByText('디바이스 목록을 불러올 수 없습니다.')).toBeInTheDocument();
    expect(screen.getByText('다시 시도')).toBeInTheDocument();
  });

  it('should display device status table', async () => {
    renderWithRouter(<Dashboard />);

    await waitFor(() => {
      expect(screen.getByText('디바이스 상태')).toBeInTheDocument();
      expect(screen.getByText('sensor-001')).toBeInTheDocument();
      expect(screen.getByText('테스트 센서')).toBeInTheDocument();
      expect(screen.getByText('active')).toBeInTheDocument();
    });
  });

  it('should display summary cards', async () => {
    renderWithRouter(<Dashboard />);

    await waitFor(() => {
      expect(screen.getByText('활성 디바이스')).toBeInTheDocument();
      expect(screen.getByText('1')).toBeInTheDocument(); // active device count
      expect(screen.getByText('총 데이터')).toBeInTheDocument();
      expect(screen.getByText('1')).toBeInTheDocument(); // total data count
    });
  });

  it('should handle empty data gracefully', () => {
    mockUseDevices.mockReturnValue({
      devices: [],
      loading: false,
      error: null,
      refetch: jest.fn()
    });

    mockUseSensorData.mockReturnValue({
      latestData: [],
      loading: false,
      error: null,
      refetch: jest.fn()
    });

    renderWithRouter(<Dashboard />);

    expect(screen.getByText('센서 대시보드')).toBeInTheDocument();
    expect(screen.getByText('활성 디바이스')).toBeInTheDocument();
    expect(screen.getByText('0')).toBeInTheDocument(); // no active devices
  });

  it('should handle sensor data with invalid values', () => {
    const invalidSensorData = [
      {
        device_id: 'sensor-001',
        temperature: 1e-40, // very small value
        humidity: undefined,
        pm10: null as any,
        pm25: Infinity,
        pressure: NaN,
        illumination: 500,
        tvoc: 120,
        co2: 450,
        o2: 20.9,
        co: 0.5,
        recorded_time: '2025-08-01T10:00:00Z'
      }
    ];

    mockUseSensorData.mockReturnValue({
      latestData: invalidSensorData,
      loading: false,
      error: null,
      refetch: jest.fn()
    });

    renderWithRouter(<Dashboard />);

    // Should display formatted values for invalid data
    expect(screen.getByText('0.0°C')).toBeInTheDocument(); // very small value
    expect(screen.getByText('N/A%')).toBeInTheDocument(); // undefined
    expect(screen.getByText('N/Aμg/m³')).toBeInTheDocument(); // null
    expect(screen.getByText('N/Aμg/m³')).toBeInTheDocument(); // Infinity
    expect(screen.getByText('N/AhPa')).toBeInTheDocument(); // NaN
  });

  it('should display all sensor types', async () => {
    const completeSensorData = [
      {
        device_id: 'sensor-001',
        temperature: 25.5,
        humidity: 60.0,
        pm10: 15.2,
        pm25: 8.1,
        pressure: 1013.25,
        illumination: 500,
        tvoc: 120,
        co2: 450,
        o2: 20.9,
        co: 0.5,
        recorded_time: '2025-08-01T10:00:00Z'
      }
    ];

    mockUseSensorData.mockReturnValue({
      latestData: completeSensorData,
      loading: false,
      error: null,
      refetch: jest.fn()
    });

    renderWithRouter(<Dashboard />);

    await waitFor(() => {
      // Check all sensor cards are rendered
      expect(screen.getByText('현재 온도')).toBeInTheDocument();
      expect(screen.getByText('현재 습도')).toBeInTheDocument();
      expect(screen.getByText('PM10')).toBeInTheDocument();
      expect(screen.getByText('PM2.5')).toBeInTheDocument();
      expect(screen.getByText('기압')).toBeInTheDocument();
      expect(screen.getByText('조도')).toBeInTheDocument();
      expect(screen.getByText('TVOC')).toBeInTheDocument();
      expect(screen.getByText('CO2')).toBeInTheDocument();
      expect(screen.getByText('O2')).toBeInTheDocument();
      expect(screen.getByText('CO')).toBeInTheDocument();
    });
  });

  it('should handle retry functionality', async () => {
    const mockRefetchDevices = jest.fn();
    const mockRefetchData = jest.fn();

    mockUseDevices.mockReturnValue({
      devices: [],
      loading: false,
      error: '디바이스 목록을 불러올 수 없습니다.',
      refetch: mockRefetchDevices
    });

    mockUseSensorData.mockReturnValue({
      latestData: [],
      loading: false,
      error: '센서 데이터를 불러올 수 없습니다.',
      refetch: mockRefetchData
    });

    renderWithRouter(<Dashboard />);

    const retryButton = screen.getByText('다시 시도');
    retryButton.click();

    expect(mockRefetchDevices).toHaveBeenCalled();
    expect(mockRefetchData).toHaveBeenCalled();
  });
}); 