import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useAreas, useCreateArea, useUpdateArea, useDeleteArea, useToggleAreaStatus } from '../../src/hooks/useAreas';
import { areaClient } from '../../src/api/areaClient';

// 完整的mock响应对象 - 按照用户UI包规范
const createMockResponse = (status: number, data?: any) => ({
  status,
  ok: status >= 200 && status < 300,
  body: null,
  bodyUsed: false,
  statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : status === 204 ? 'No Content' : 'Error',
  headers: new Headers(),
  url: '',
  redirected: false,
  type: 'basic' as ResponseType,
  json: async () => data || {},
  text: async () => '',
  blob: async () => new Blob(),
  arrayBuffer: async () => new ArrayBuffer(0),
  formData: async () => new FormData(),
  clone: function() { return this; }
});

// Mock areaClient - 按照用户UI包规范
vi.mock('../../src/api/areaClient', () => {
  const mockAreaClient = {
    index: {
      $get: vi.fn(() => Promise.resolve({ status: 200, body: null })),
      $post: vi.fn(() => Promise.resolve({ status: 201, body: null })),
    },
    ':id': {
      $put: vi.fn(() => Promise.resolve({ status: 200, body: null })),
      $delete: vi.fn(() => Promise.resolve({ status: 204, body: null })),
    },
  };

  const mockAreaClientManager = {
    get: vi.fn(() => mockAreaClient),
  };

  return {
    areaClientManager: mockAreaClientManager,
    areaClient: mockAreaClient,
  };
});

// Mock sonner toast
vi.mock('sonner', () => ({
  toast: {
    success: vi.fn(),
    error: vi.fn()
  }
}));

// Test wrapper component
const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
      },
    },
  });

  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  );
};

describe('useAreas Hook', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should fetch areas successfully', async () => {
    const mockAreas = [
      {
        id: 1,
        name: '北京市',
        code: '110000',
        level: 1,
        parentId: null,
        isDisabled: 0
      }
    ];

    (areaClient.index.$get as any).mockResolvedValueOnce(createMockResponse(200, { data: mockAreas }));

    const { result } = renderHook(() => useAreas(), {
      wrapper: createWrapper()
    });

    // Initial loading state
    expect(result.current.isLoading).toBe(true);

    // Wait for data to load
    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toEqual(mockAreas);
    expect(areaClient.index.$get).toHaveBeenCalledWith({
      query: {
        page: 1,
        pageSize: 100,
        filters: '',
        sortBy: 'id',
        sortOrder: 'ASC'
      }
    });
  });

  it('should handle fetch areas error', async () => {
    (areaClient.index.$get as any).mockRejectedValueOnce(new Error('API Error'));

    const { result } = renderHook(() => useAreas(), {
      wrapper: createWrapper()
    });

    // Wait for error
    await waitFor(() => {
      expect(result.current.isError).toBe(true);
    });

    expect(result.current.error).toBeDefined();
  });

  it('should create area successfully', async () => {
    const mockAreaData = {
      name: '北京市',
      code: '110000',
      level: 1,
      parentId: null,
      isDisabled: 0
    };

    (areaClient.index.$post as any).mockResolvedValueOnce(createMockResponse(201));

    const { result } = renderHook(() => useCreateArea(), {
      wrapper: createWrapper()
    });

    await result.current.mutateAsync(mockAreaData);

    expect(areaClient.index.$post).toHaveBeenCalledWith({
      json: mockAreaData
    });
  });

  it('should update area successfully', async () => {
    const mockUpdateData = {
      name: '北京市更新',
      code: '110000',
      level: 1,
      parentId: null,
      isDisabled: 0
    };

    (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));

    const { result } = renderHook(() => useUpdateArea(), {
      wrapper: createWrapper()
    });

    await result.current.mutateAsync({
      id: 1,
      data: mockUpdateData
    });

    expect(areaClient[':id'].$put).toHaveBeenCalledWith({
      param: { id: 1 },
      json: mockUpdateData
    });
  });

  it('should delete area successfully', async () => {
    (areaClient[':id'].$delete as any).mockResolvedValueOnce(createMockResponse(204));

    const { result } = renderHook(() => useDeleteArea(), {
      wrapper: createWrapper()
    });

    await result.current.mutateAsync(1);

    expect(areaClient[':id'].$delete).toHaveBeenCalledWith({
      param: { id: 1 }
    });
  });

  it('should toggle area status successfully', async () => {
    (areaClient[':id'].$put as any).mockResolvedValueOnce(createMockResponse(200));

    const { result } = renderHook(() => useToggleAreaStatus(), {
      wrapper: createWrapper()
    });

    await result.current.mutateAsync({
      id: 1,
      isDisabled: 1
    });

    expect(areaClient[':id'].$put).toHaveBeenCalledWith({
      param: { id: 1 },
      json: { isDisabled: 1 }
    });
  });
});