import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, waitFor, act } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';

// Mock apiClient
vi.mock('../../api/client', () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    patch: vi.fn(),
    delete: vi.fn(),
  },
}));

import {
  usePlatformSettings,
  useUpdateGeneralSettings,
  useUpdateStripeKeys,
  useValidateStripeKeys,
  useSubscriptionPlans,
  useCreateSubscriptionPlan,
  useUpdateSubscriptionPlan,
  useDeleteSubscriptionPlan,
  useSyncPlansWithStripe,
  useSyncPlanToTenants,
} from '../usePlatformSettings';
import apiClient from '../../api/client';

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

  return function Wrapper({ children }: { children: React.ReactNode }) {
    return React.createElement(QueryClientProvider, { client: queryClient }, children);
  };
};

describe('usePlatformSettings hooks', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('usePlatformSettings', () => {
    it('fetches platform settings successfully', async () => {
      const mockSettings = {
        stripe_secret_key_masked: 'sk_test_***',
        stripe_publishable_key_masked: 'pk_test_***',
        stripe_webhook_secret_masked: 'whsec_***',
        stripe_account_id: 'acct_123',
        stripe_account_name: 'Test Account',
        stripe_keys_validated_at: '2025-12-07T10:00:00Z',
        stripe_validation_error: '',
        has_stripe_keys: true,
        stripe_keys_from_env: false,
        email_check_interval_minutes: 5,
        updated_at: '2025-12-07T10:00:00Z',
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockSettings });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/platform/settings/');
      expect(result.current.data).toEqual(mockSettings);
    });

    it('handles fetch error', async () => {
      vi.mocked(apiClient.get).mockRejectedValue(new Error('Network error'));

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

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

      expect(result.current.error).toBeInstanceOf(Error);
    });

    it('uses staleTime of 5 minutes', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: {} });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

      renderHook(() => usePlatformSettings(), { wrapper });

      await waitFor(() => {
        expect(apiClient.get).toHaveBeenCalled();
      });

      // Query should be cached with 5 minute stale time
      const cachedQuery = queryClient.getQueryState(['platformSettings']);
      expect(cachedQuery).toBeDefined();
    });
  });

  describe('useUpdateGeneralSettings', () => {
    it('updates general settings successfully', async () => {
      const updatedSettings = {
        email_check_interval_minutes: 10,
        updated_at: '2025-12-07T11:00:00Z',
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: updatedSettings });

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

      await act(async () => {
        await result.current.mutateAsync({
          email_check_interval_minutes: 10,
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/settings/general/', {
        email_check_interval_minutes: 10,
      });

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

    it('updates query cache on success', async () => {
      const updatedSettings = {
        stripe_secret_key_masked: 'sk_test_***',
        stripe_publishable_key_masked: 'pk_test_***',
        stripe_webhook_secret_masked: 'whsec_***',
        stripe_account_id: 'acct_123',
        stripe_account_name: 'Test Account',
        stripe_keys_validated_at: null,
        stripe_validation_error: '',
        has_stripe_keys: true,
        stripe_keys_from_env: false,
        email_check_interval_minutes: 15,
        updated_at: '2025-12-07T11:00:00Z',
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: updatedSettings });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync({
          email_check_interval_minutes: 15,
        });
      });

      const cachedData = queryClient.getQueryData(['platformSettings']);
      expect(cachedData).toEqual(updatedSettings);
    });

    it('handles update error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Update failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync({ email_check_interval_minutes: 5 });
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useUpdateStripeKeys', () => {
    it('updates Stripe keys successfully', async () => {
      const updatedSettings = {
        stripe_secret_key_masked: 'sk_live_***',
        stripe_publishable_key_masked: 'pk_live_***',
        stripe_webhook_secret_masked: 'whsec_***',
        has_stripe_keys: true,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: updatedSettings });

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

      await act(async () => {
        await result.current.mutateAsync({
          stripe_secret_key: 'sk_live_newkey',
          stripe_publishable_key: 'pk_live_newkey',
          stripe_webhook_secret: 'whsec_newsecret',
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/settings/stripe/keys/', {
        stripe_secret_key: 'sk_live_newkey',
        stripe_publishable_key: 'pk_live_newkey',
        stripe_webhook_secret: 'whsec_newsecret',
      });

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

    it('updates partial Stripe keys', async () => {
      const updatedSettings = {
        stripe_secret_key_masked: 'sk_live_***',
        has_stripe_keys: true,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: updatedSettings });

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

      await act(async () => {
        await result.current.mutateAsync({
          stripe_secret_key: 'sk_live_newkey',
        });
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/settings/stripe/keys/', {
        stripe_secret_key: 'sk_live_newkey',
      });
    });

    it('updates query cache on success', async () => {
      const updatedSettings = {
        stripe_secret_key_masked: 'sk_live_***',
        has_stripe_keys: true,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: updatedSettings });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync({
          stripe_secret_key: 'sk_live_newkey',
        });
      });

      const cachedData = queryClient.getQueryData(['platformSettings']);
      expect(cachedData).toEqual(updatedSettings);
    });
  });

  describe('useValidateStripeKeys', () => {
    it('validates Stripe keys successfully', async () => {
      const responseData = {
        success: true,
        message: 'Stripe keys validated successfully',
        settings: {
          stripe_keys_validated_at: '2025-12-07T12:00:00Z',
          stripe_validation_error: '',
          stripe_account_id: 'acct_123',
          stripe_account_name: 'Test Account',
        },
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: responseData });

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

      await act(async () => {
        await result.current.mutateAsync();
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/settings/stripe/validate/');

      await waitFor(() => {
        expect(result.current.data).toEqual(responseData);
      });
    });

    it('updates query cache with settings on success', async () => {
      const updatedSettings = {
        stripe_keys_validated_at: '2025-12-07T12:00:00Z',
        stripe_validation_error: '',
        stripe_account_id: 'acct_123',
        stripe_account_name: 'Test Account',
      };
      const responseData = {
        success: true,
        message: 'Validated',
        settings: updatedSettings,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: responseData });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync();
      });

      const cachedData = queryClient.getQueryData(['platformSettings']);
      expect(cachedData).toEqual(updatedSettings);
    });

    it('does not update cache when settings is not in response', async () => {
      const responseData = {
        success: false,
        message: 'Invalid keys',
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: responseData });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync();
      });

      const cachedData = queryClient.getQueryData(['platformSettings']);
      expect(cachedData).toBeUndefined();
    });

    it('handles validation error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Validation failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync();
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useSubscriptionPlans', () => {
    it('fetches subscription plans successfully', async () => {
      const mockPlans = [
        {
          id: 1,
          name: 'Basic',
          description: 'Basic plan',
          plan_type: 'base' as const,
          stripe_product_id: 'prod_123',
          stripe_price_id: 'price_123',
          price_monthly: '29.99',
          price_yearly: '299.99',
          business_tier: 'basic',
          features: ['feature1', 'feature2'],
          limits: { max_users: 10 },
          permissions: { can_use_plugins: false },
          transaction_fee_percent: '2.5',
          transaction_fee_fixed: '0.30',
          sms_enabled: true,
          sms_price_per_message_cents: 5,
          masked_calling_enabled: false,
          masked_calling_price_per_minute_cents: 0,
          proxy_number_enabled: false,
          proxy_number_monthly_fee_cents: 0,
          contracts_enabled: false,
          default_auto_reload_enabled: true,
          default_auto_reload_threshold_cents: 500,
          default_auto_reload_amount_cents: 2000,
          is_active: true,
          is_public: true,
          is_most_popular: false,
          show_price: true,
          created_at: '2025-12-01T10:00:00Z',
          updated_at: '2025-12-07T10:00:00Z',
        },
        {
          id: 2,
          name: 'Pro',
          description: 'Pro plan',
          plan_type: 'base' as const,
          stripe_product_id: 'prod_456',
          stripe_price_id: 'price_456',
          price_monthly: '99.99',
          price_yearly: null,
          business_tier: 'pro',
          features: ['feature1', 'feature2', 'feature3'],
          limits: { max_users: 50 },
          permissions: { can_use_plugins: true },
          transaction_fee_percent: '2.0',
          transaction_fee_fixed: '0.30',
          sms_enabled: true,
          sms_price_per_message_cents: 4,
          masked_calling_enabled: true,
          masked_calling_price_per_minute_cents: 10,
          proxy_number_enabled: true,
          proxy_number_monthly_fee_cents: 1500,
          contracts_enabled: true,
          default_auto_reload_enabled: false,
          default_auto_reload_threshold_cents: 0,
          default_auto_reload_amount_cents: 0,
          is_active: true,
          is_public: true,
          is_most_popular: true,
          show_price: true,
          created_at: '2025-12-01T10:00:00Z',
          updated_at: '2025-12-07T10:00:00Z',
        },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockPlans });

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

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

      expect(apiClient.get).toHaveBeenCalledWith('/platform/subscription-plans/');
      expect(result.current.data).toEqual(mockPlans);
      expect(result.current.data).toHaveLength(2);
    });

    it('handles fetch error', async () => {
      vi.mocked(apiClient.get).mockRejectedValue(new Error('Network error'));

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

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

      expect(result.current.error).toBeInstanceOf(Error);
    });

    it('uses staleTime of 5 minutes', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
        },
      });

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

      renderHook(() => useSubscriptionPlans(), { wrapper });

      await waitFor(() => {
        expect(apiClient.get).toHaveBeenCalled();
      });

      const cachedQuery = queryClient.getQueryState(['subscriptionPlans']);
      expect(cachedQuery).toBeDefined();
    });
  });

  describe('useCreateSubscriptionPlan', () => {
    it('creates subscription plan successfully', async () => {
      const newPlan = {
        name: 'Enterprise',
        description: 'Enterprise plan',
        plan_type: 'base' as const,
        price_monthly: 199.99,
        price_yearly: 1999.99,
        business_tier: 'enterprise',
        features: ['all_features'],
        limits: { max_users: 100 },
        permissions: { can_use_plugins: true },
        transaction_fee_percent: 1.5,
        transaction_fee_fixed: 0.30,
        create_stripe_product: true,
      };

      const createdPlan = {
        id: 3,
        ...newPlan,
        price_monthly: '199.99',
        price_yearly: '1999.99',
        transaction_fee_percent: '1.5',
        transaction_fee_fixed: '0.30',
        stripe_product_id: 'prod_789',
        stripe_price_id: 'price_789',
        sms_enabled: false,
        sms_price_per_message_cents: 0,
        masked_calling_enabled: false,
        masked_calling_price_per_minute_cents: 0,
        proxy_number_enabled: false,
        proxy_number_monthly_fee_cents: 0,
        contracts_enabled: false,
        default_auto_reload_enabled: false,
        default_auto_reload_threshold_cents: 0,
        default_auto_reload_amount_cents: 0,
        is_active: true,
        is_public: true,
        is_most_popular: false,
        show_price: true,
        created_at: '2025-12-07T12:00:00Z',
        updated_at: '2025-12-07T12:00:00Z',
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: createdPlan });

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

      await act(async () => {
        await result.current.mutateAsync(newPlan);
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/subscription-plans/', newPlan);

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

    it('creates plan with minimal data', async () => {
      const minimalPlan = {
        name: 'Minimal Plan',
      };

      const createdPlan = {
        id: 4,
        name: 'Minimal Plan',
        description: '',
        plan_type: 'base' as const,
        stripe_product_id: '',
        stripe_price_id: '',
        price_monthly: null,
        price_yearly: null,
        business_tier: '',
        features: [],
        limits: {},
        permissions: {},
        transaction_fee_percent: '0',
        transaction_fee_fixed: '0',
        sms_enabled: false,
        sms_price_per_message_cents: 0,
        masked_calling_enabled: false,
        masked_calling_price_per_minute_cents: 0,
        proxy_number_enabled: false,
        proxy_number_monthly_fee_cents: 0,
        contracts_enabled: false,
        default_auto_reload_enabled: false,
        default_auto_reload_threshold_cents: 0,
        default_auto_reload_amount_cents: 0,
        is_active: true,
        is_public: false,
        is_most_popular: false,
        show_price: false,
        created_at: '2025-12-07T12:00:00Z',
        updated_at: '2025-12-07T12:00:00Z',
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: createdPlan });

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

      await act(async () => {
        await result.current.mutateAsync(minimalPlan);
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/subscription-plans/', minimalPlan);
    });

    it('invalidates subscription plans query on success', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: { id: 5 } });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      // Spy on invalidateQueries
      const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync({ name: 'Test Plan' });
      });

      expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['subscriptionPlans'] });
    });

    it('handles create error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Create failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync({ name: 'Test' });
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useUpdateSubscriptionPlan', () => {
    it('updates subscription plan successfully', async () => {
      const updates = {
        id: 1,
        name: 'Updated Basic',
        price_monthly: 39.99,
        is_most_popular: true,
      };

      const updatedPlan = {
        id: 1,
        name: 'Updated Basic',
        price_monthly: '39.99',
        is_most_popular: true,
        description: 'Basic plan',
        plan_type: 'base' as const,
        stripe_product_id: 'prod_123',
        stripe_price_id: 'price_123',
        price_yearly: '299.99',
        business_tier: 'basic',
        features: ['feature1', 'feature2'],
        limits: { max_users: 10 },
        permissions: { can_use_plugins: false },
        transaction_fee_percent: '2.5',
        transaction_fee_fixed: '0.30',
        sms_enabled: true,
        sms_price_per_message_cents: 5,
        masked_calling_enabled: false,
        masked_calling_price_per_minute_cents: 0,
        proxy_number_enabled: false,
        proxy_number_monthly_fee_cents: 0,
        contracts_enabled: false,
        default_auto_reload_enabled: true,
        default_auto_reload_threshold_cents: 500,
        default_auto_reload_amount_cents: 2000,
        is_active: true,
        is_public: true,
        show_price: true,
        created_at: '2025-12-01T10:00:00Z',
        updated_at: '2025-12-07T13:00:00Z',
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: updatedPlan });

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

      await act(async () => {
        await result.current.mutateAsync(updates);
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/platform/subscription-plans/1/', {
        name: 'Updated Basic',
        price_monthly: 39.99,
        is_most_popular: true,
      });

      await waitFor(() => {
        expect(result.current.data).toEqual(updatedPlan);
      });
    });

    it('updates only specified fields', async () => {
      const updates = {
        id: 2,
        is_active: false,
      };

      vi.mocked(apiClient.patch).mockResolvedValue({ data: { id: 2, is_active: false } });

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

      await act(async () => {
        await result.current.mutateAsync(updates);
      });

      expect(apiClient.patch).toHaveBeenCalledWith('/platform/subscription-plans/2/', {
        is_active: false,
      });
    });

    it('invalidates subscription plans query on success', async () => {
      vi.mocked(apiClient.patch).mockResolvedValue({ data: { id: 1 } });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync({ id: 1, name: 'Updated' });
      });

      expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['subscriptionPlans'] });
    });

    it('handles update error', async () => {
      vi.mocked(apiClient.patch).mockRejectedValue(new Error('Update failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync({ id: 1, name: 'Fail' });
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useDeleteSubscriptionPlan', () => {
    it('deletes subscription plan successfully', async () => {
      vi.mocked(apiClient.delete).mockResolvedValue({ data: { success: true } });

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

      await act(async () => {
        await result.current.mutateAsync(3);
      });

      expect(apiClient.delete).toHaveBeenCalledWith('/platform/subscription-plans/3/');

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

    it('invalidates subscription plans query on success', async () => {
      vi.mocked(apiClient.delete).mockResolvedValue({});

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync(5);
      });

      expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['subscriptionPlans'] });
    });

    it('handles delete error', async () => {
      vi.mocked(apiClient.delete).mockRejectedValue(new Error('Delete failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync(1);
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useSyncPlansWithStripe', () => {
    it('syncs plans with Stripe successfully', async () => {
      const syncResponse = {
        success: true,
        message: 'Plans synced successfully',
        synced_count: 3,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: syncResponse });

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

      await act(async () => {
        await result.current.mutateAsync();
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/subscription-plans/sync_with_stripe/');

      await waitFor(() => {
        expect(result.current.data).toEqual(syncResponse);
      });
    });

    it('invalidates subscription plans query on success', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: { success: true } });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync();
      });

      expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['subscriptionPlans'] });
    });

    it('handles sync error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Sync failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync();
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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

  describe('useSyncPlanToTenants', () => {
    it('syncs plan to tenants successfully', async () => {
      const syncResponse = {
        message: 'Plan synced to 15 tenants',
        tenant_count: 15,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: syncResponse });

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

      await act(async () => {
        await result.current.mutateAsync(1);
      });

      expect(apiClient.post).toHaveBeenCalledWith('/platform/subscription-plans/1/sync_tenants/');

      await waitFor(() => {
        expect(result.current.data).toEqual(syncResponse);
      });
    });

    it('handles zero tenants', async () => {
      const syncResponse = {
        message: 'No tenants on this plan',
        tenant_count: 0,
      };
      vi.mocked(apiClient.post).mockResolvedValue({ data: syncResponse });

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

      await act(async () => {
        await result.current.mutateAsync(5);
      });

      await waitFor(() => {
        expect(result.current.data?.tenant_count).toBe(0);
      });
    });

    it('does not invalidate queries (no onSuccess callback)', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'Done', tenant_count: 5 } });

      const queryClient = new QueryClient({
        defaultOptions: {
          queries: { retry: false },
          mutations: { retry: false },
        },
      });

      const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');

      const wrapper = ({ children }: { children: React.ReactNode }) =>
        React.createElement(QueryClientProvider, { client: queryClient }, children);

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

      await act(async () => {
        await result.current.mutateAsync(2);
      });

      // This mutation does not have an onSuccess callback, so it shouldn't invalidate
      expect(invalidateQueriesSpy).not.toHaveBeenCalled();
    });

    it('handles sync error', async () => {
      vi.mocked(apiClient.post).mockRejectedValue(new Error('Sync to tenants failed'));

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

      await act(async () => {
        try {
          await result.current.mutateAsync(1);
        } catch (error) {
          expect(error).toBeInstanceOf(Error);
        }
      });

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