import { renderHook, act, waitFor } from '@testing-library/react-native'
import { useMembership } from './use-membership'
import { subscription, useSession } from '@/lib/auth'

jest.mock('@/lib/auth', () => ({
  subscription: {
    plans: jest.fn(),
    list: jest.fn(),
    create: jest.fn(),
    upgrade: jest.fn(),
    restore: jest.fn(),
    cancel: jest.fn(),
    credit: {
      topup: jest.fn(),
    },
  },
  useSession: jest.fn(),
}))

describe('useMembership', () => {
  const mockSession = {
    user: { id: 'user-123' },
  }

  beforeEach(() => {
    jest.clearAllMocks()
    ;(useSession as jest.Mock).mockReturnValue({ data: mockSession })
    ;(subscription.list as jest.Mock).mockResolvedValue({ data: [], error: null })
  })

  describe('获取 Stripe 定价表数据', () => {
    it('应该成功获取定价表数据', async () => {
      const mockPricingData = {
        pricing_table_items: [
          {
            amount: '1000',
            recurring: { interval: 'month' },
            metadata: { grant_token: '1000' },
            is_highlight: true,
          },
        ],
      }
      ;(subscription.plans as jest.Mock).mockResolvedValue({
        data: mockPricingData,
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(result.current.stripePricingData).toEqual(mockPricingData)
      })

      expect(subscription.plans).toHaveBeenCalledWith({
        query: {
          id: '',
          key: '',
        },
      })
    })

    it('应该处理定价表获取错误', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({
        data: null,
        error: { message: 'Failed to fetch pricing' },
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(subscription.plans).toHaveBeenCalled()
      })

      expect(result.current.stripePricingData).toBeNull()
    })
  })

  describe('获取用户订阅列表', () => {
    it('应该成功获取订阅列表', async () => {
      const mockSubscriptions = [
        {
          type: 'licenced',
          status: 'active',
          cancelAtPeriodEnd: false,
          stripeSubscriptionId: 'sub-123',
        },
      ]
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({
        data: mockSubscriptions,
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(subscription.list).toHaveBeenCalledWith({
          query: { referenceId: 'user-123' },
        })
      })
    })

    it('应该在没有用户会话时不获取订阅', () => {
      ;(useSession as jest.Mock).mockReturnValue({ data: null })
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })

      renderHook(() => useMembership())

      expect(subscription.list).not.toHaveBeenCalled()
    })
  })

  describe('创建订阅', () => {
    it('应该调用 subscription.create', async () => {
      const mockUrl = 'https://checkout.stripe.com/test'
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.create as jest.Mock).mockResolvedValue({
        data: { url: mockUrl },
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await act(async () => {
        await result.current.createSubscription({
          priceId: 'price-123',
          productId: 'prod-123',
        })
      })

      expect(subscription.create).toHaveBeenCalledWith({
        priceId: 'price-123',
        productId: 'prod-123',
        successUrl: expect.stringContaining('/membership'),
        cancelUrl: expect.stringContaining('/membership?canceled=true'),
      })
    })

    it('应该处理创建订阅错误', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.create as jest.Mock).mockResolvedValue({
        data: null,
        error: { message: 'Failed to create subscription' },
      })

      const { result } = renderHook(() => useMembership())

      await act(async () => {
        await result.current.createSubscription({
          priceId: 'price-123',
          productId: 'prod-123',
        })
      })

      expect(subscription.create).toHaveBeenCalled()
    })
  })

  describe('升级订阅', () => {
    it('应该成功升级订阅', async () => {
      const mockPricingData = {
        pricing_table_items: [
          { amount: '1000', product_name: 'basic', recurring: { interval: 'month' }, metadata: { grant_token: '1000' } },
        ],
      }
      const mockSubscriptions = [
        {
          type: 'licenced',
          status: 'active',
          cancelAtPeriodEnd: false,
          stripeSubscriptionId: 'sub-123',
        },
      ]
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: mockPricingData, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockSubscriptions, error: null })
      ;(subscription.upgrade as jest.Mock).mockResolvedValue({
        data: { success: true },
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(result.current.activeAuthSubscription).toBeDefined()
      })

      await act(async () => {
        await result.current.upgradeSubscription({ credits: 1000 })
      })

      expect(subscription.upgrade).toHaveBeenCalled()
    })

    it('应该处理未找到活跃订阅的情况', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: [], error: null })

      const { result } = renderHook(() => useMembership())

      await act(async () => {
        await result.current.upgradeSubscription({ credits: 1000 })
      })

      expect(subscription.upgrade).not.toHaveBeenCalled()
    })
  })

  describe('恢复订阅', () => {
    it('应该成功恢复订阅', async () => {
      const mockSubscriptions = [
        {
          type: 'licenced',
          status: 'active',
          cancelAtPeriodEnd: true,
          stripeSubscriptionId: 'sub-123',
          referenceId: 'user-123',
        },
      ]
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockSubscriptions, error: null })
      ;(subscription.restore as jest.Mock).mockResolvedValue({
        data: { success: true },
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(result.current.activeAuthSubscription).toBeDefined()
      })

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

      expect(subscription.restore).toHaveBeenCalledWith({
        subscriptionId: 'sub-123',
        referenceId: 'user-123',
      })
    })

    it('应该处理未找到可恢复订阅的情况', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: [], error: null })

      const { result } = renderHook(() => useMembership())

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

      expect(subscription.restore).not.toHaveBeenCalled()
    })
  })

  describe('充值积分', () => {
    it('应该成功充值积分', async () => {
      const mockUrl = 'https://checkout.stripe.com/topup'
      const mockSubscriptions = [
        {
          type: 'metered',
          priceId: 'price-metered-123',
          creditBalance: { remainingTokenBalance: 100 },
        },
      ]
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockSubscriptions, error: null })
      ;(subscription.credit.topup as jest.Mock).mockResolvedValue({
        data: { url: mockUrl },
        error: null,
      })

      const { result } = renderHook(() => useMembership())

      await waitFor(() => {
        expect(result.current.creditBalance).toBe(100)
      })

      await act(async () => {
        await result.current.rechargeToken(1000)
      })

      expect(subscription.credit.topup).toHaveBeenCalledWith({
        amount: 1000,
        priceId: 'price-metered-123',
        successUrl: expect.stringContaining('/membership'),
        cancelUrl: expect.stringContaining('/membership?canceled=true'),
      })
    })

    it('应该处理无效充值金额', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })

      const { result } = renderHook(() => useMembership())

      await act(async () => {
        await result.current.rechargeToken(0)
      })

      expect(subscription.credit.topup).not.toHaveBeenCalled()
    })

    it('应该处理定价数据不可用的情况', async () => {
      ;(subscription.plans as jest.Mock).mockResolvedValue({ data: null, error: null })
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: [], error: null })

      const { result } = renderHook(() => useMembership())

      await act(async () => {
        await result.current.rechargeToken(1000)
      })

      expect(subscription.credit.topup).not.toHaveBeenCalled()
    })
  })
})
