import { act, renderHook } from '@testing-library/react-native'

import { useUserBalanceStore } from '@/stores/userBalanceStore'
import { subscription } from '@/lib/auth'

// Mock subscription API
jest.mock('@/lib/auth', () => ({
  subscription: {
    list: jest.fn(),
  },
}))

// Mock AppState
jest.mock('react-native', () => ({
  AppState: {
    addEventListener: jest.fn(() => ({ remove: jest.fn() })),
  },
}))

describe('userBalanceStore', () => {
  beforeEach(() => {
    // Reset store state before each test
    const { reset } = useUserBalanceStore.getState()
    reset()
    jest.clearAllMocks()
  })

  describe('load', () => {
    it('should load balance from API', async () => {
      const mockData = [
        {
          type: 'metered',
          creditBalance: {
            remainingTokenBalance: 1000,
          },
        },
      ]
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData })

      const { load } = useUserBalanceStore.getState()
      await act(async () => {
        await load(true)
      })

      const { balance } = useUserBalanceStore.getState()
      expect(balance).toBe(1000)
    })

    it('should handle API error', async () => {
      const mockError = { message: 'API Error', status: 500, statusText: 'Internal Server Error' }
      ;(subscription.list as jest.Mock).mockResolvedValue({ error: mockError })

      const { load } = useUserBalanceStore.getState()
      await act(async () => {
        await load(true)
      })

      const { error } = useUserBalanceStore.getState()
      expect(error).toEqual(mockError)
    })

    it('should debounce requests within 5 seconds', async () => {
      const mockData = [
        {
          type: 'metered',
          creditBalance: {
            remainingTokenBalance: 500,
          },
        },
      ]
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData })

      const { load } = useUserBalanceStore.getState()

      // First call
      await act(async () => {
        await load(false)
      })

      // Second call within 5 seconds (should be skipped)
      await act(async () => {
        await load(false)
      })

      // API should only be called once
      expect(subscription.list).toHaveBeenCalledTimes(1)
    })

    it('should force load when force=true', async () => {
      const mockData = [
        {
          type: 'metered',
          creditBalance: {
            remainingTokenBalance: 500,
          },
        },
      ]
      ;(subscription.list as jest.Mock).mockResolvedValue({ data: mockData })

      const { load } = useUserBalanceStore.getState()

      // First call
      await act(async () => {
        await load(true)
      })

      // Second call with force=true (should not be skipped)
      await act(async () => {
        await load(true)
      })

      // API should be called twice
      expect(subscription.list).toHaveBeenCalledTimes(2)
    })
  })

  describe('setBalance', () => {
    it('should set balance directly', () => {
      const { setBalance } = useUserBalanceStore.getState()

      act(() => {
        setBalance(2000)
      })

      const { balance } = useUserBalanceStore.getState()
      expect(balance).toBe(2000)
    })
  })

  describe('deductBalance', () => {
    it('should deduct balance', () => {
      const { setBalance, deductBalance } = useUserBalanceStore.getState()

      act(() => {
        setBalance(1000)
        deductBalance(300)
      })

      const { balance } = useUserBalanceStore.getState()
      expect(balance).toBe(700)
    })

    it('should not go below zero', () => {
      const { setBalance, deductBalance } = useUserBalanceStore.getState()

      act(() => {
        setBalance(100)
        deductBalance(500)
      })

      const { balance } = useUserBalanceStore.getState()
      expect(balance).toBe(0)
    })
  })

  describe('reset', () => {
    it('should reset all state', () => {
      const { setBalance, reset } = useUserBalanceStore.getState()

      act(() => {
        setBalance(5000)
      })

      expect(useUserBalanceStore.getState().balance).toBe(5000)

      act(() => {
        reset()
      })

      const state = useUserBalanceStore.getState()
      expect(state.balance).toBe(0)
      expect(state.loading).toBe(false)
      expect(state.error).toBe(null)
    })
  })
})
