import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { renderHook, waitFor, act } from '@testing-library/react-native';
import React, { type PropsWithChildren } from 'react';

import {
  useProfile,
  useUpdateProfile,
  useCurrentPlan,
  useQuota,
  useFaqs,
  useSubmitFeedback,
  useLegalDoc,
} from '@/features/profile/hooks';

// ─── Mocks ───

const mockFetchProfile = jest.fn();
const mockUpdateProfile = jest.fn();
const mockFetchCurrentPlan = jest.fn();
const mockCheckQuota = jest.fn();
const mockFetchFaqs = jest.fn();
const mockSubmitFeedback = jest.fn();
const mockFetchLegalDoc = jest.fn();

jest.mock('@/features/profile/api', () => ({
  profileApi: {
    fetchProfile: () => mockFetchProfile(),
    updateProfile: (body: unknown) => mockUpdateProfile(body),
    fetchPlans: jest.fn(),
    fetchCurrentPlan: () => mockFetchCurrentPlan(),
    checkQuota: () => mockCheckQuota(),
    fetchFaqs: () => mockFetchFaqs(),
    submitFeedback: (body: unknown) => mockSubmitFeedback(body),
    fetchLegalDoc: (type: string) => mockFetchLegalDoc(type),
  },
}));

// ─── Helpers ───

let queryClient: QueryClient;

function createWrapper() {
  queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false, gcTime: Infinity },
      mutations: { retry: false },
    },
  });

  return function Wrapper({ children }: PropsWithChildren) {
    return (
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    );
  };
}

afterEach(async () => {
  await queryClient?.cancelQueries();
  queryClient?.clear();
  jest.clearAllMocks();
});

const fakeProfile = {
  id: 'u1',
  phone: '13800138000',
  email: null,
  nickname: 'Test',
  avatar_url: null,
  subscription_type: 'free',
  created_at: '2026-01-01T00:00:00Z',
  birth_year: 1990,
  birth_place: '北京',
  grew_up_place: '上海',
  occupation: '工程师',
};

// ─── Tests ───

describe('useProfile', () => {
  test('fetches user profile', async () => {
    mockFetchProfile.mockResolvedValue(fakeProfile);

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

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toEqual(fakeProfile);
  });
});

describe('useUpdateProfile', () => {
  test('updates profile and sets cache on success', async () => {
    const updated = { ...fakeProfile, occupation: '设计师' };
    mockUpdateProfile.mockResolvedValue(updated);

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

    await act(async () => {
      result.current.mutate({ occupation: '设计师' });
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(mockUpdateProfile).toHaveBeenCalledWith({ occupation: '设计师' });
  });
});

describe('useCurrentPlan', () => {
  test('fetches current plan', async () => {
    const plan = {
      plan_id: 'free',
      plan_name: '免费版',
      subscription_type: 'free',
      expires_at: null,
      features: ['基础对话'],
      usage: {
        conversations: 2,
        chapters: 1,
        max_conversations: 5,
        max_chapters: 3,
      },
    };
    mockFetchCurrentPlan.mockResolvedValue(plan);

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

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data?.plan_name).toBe('免费版');
  });
});

describe('useQuota', () => {
  test('fetches quota check', async () => {
    const quota = {
      has_quota: true,
      remaining_conversations: 3,
      remaining_chapters: 2,
      remaining_words: null,
      used_conversations: 2,
      used_chapters: 1,
      max_conversations: 5,
      max_chapters: 3,
      message: 'OK',
    };
    mockCheckQuota.mockResolvedValue(quota);

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

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data?.has_quota).toBe(true);
    expect(result.current.data?.remaining_conversations).toBe(3);
  });
});

describe('useFaqs', () => {
  test('fetches FAQ list', async () => {
    const faqs = [
      {
        id: 'f1',
        question: '如何使用？',
        answer: '点击开始',
        category: 'general',
        order: 1,
      },
    ];
    mockFetchFaqs.mockResolvedValue(faqs);

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

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toHaveLength(1);
    expect(result.current.data?.[0].question).toBe('如何使用？');
  });
});

describe('useSubmitFeedback', () => {
  test('submits feedback', async () => {
    mockSubmitFeedback.mockResolvedValue({ id: 'fb1', message: '感谢反馈' });

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

    await act(async () => {
      result.current.mutate({ content: '很好用' });
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(mockSubmitFeedback).toHaveBeenCalledWith({ content: '很好用' });
  });
});

describe('useLegalDoc', () => {
  test('fetches terms HTML', async () => {
    mockFetchLegalDoc.mockResolvedValue(
      '<html><body><h1>用户协议</h1></body></html>',
    );

    const { result } = renderHook(() => useLegalDoc('terms'), {
      wrapper: createWrapper(),
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(result.current.data).toContain('<h1>用户协议</h1>');
    expect(mockFetchLegalDoc).toHaveBeenCalledWith('terms');
  });

  test('fetches privacy HTML', async () => {
    mockFetchLegalDoc.mockResolvedValue(
      '<html><body><h1>隐私政策</h1></body></html>',
    );

    const { result } = renderHook(() => useLegalDoc('privacy'), {
      wrapper: createWrapper(),
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBe(true);
    });

    expect(mockFetchLegalDoc).toHaveBeenCalledWith('privacy');
  });
});
