import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { createMemoryHistory, createRouter } from 'vue-router'
import ParentLayout from '../../layout/ParentLayout.vue'

// ── Hoisted mocks ────────────────────────────────────────────────────────────

let capturedChoreHandler: ((event: any) => void) | null = null
let capturedRewardHandler: ((event: any) => void) | null = null

vi.mock('@/common/eventBus', () => ({
  eventBus: {
    on: vi.fn((event: string, handler: (e: any) => void) => {
      if (event === 'child_chore_confirmation') capturedChoreHandler = handler
      if (event === 'child_reward_request') capturedRewardHandler = handler
    }),
    off: vi.fn(),
  },
}))

vi.mock('@/common/backendEvents', () => ({ useBackendEvents: vi.fn() }))

// Stub fetch: /api/pending-confirmations returns count, /api/version returns version
const mockFetch = vi.fn().mockImplementation((url: string) => {
  if (url === '/api/pending-confirmations') {
    return Promise.resolve({
      ok: true,
      json: () => Promise.resolve({ confirmations: [] }),
    })
  }
  if (url === '/api/version') {
    return Promise.resolve({
      ok: true,
      json: () => Promise.resolve({ version: '1.0.0' }),
    })
  }
  return Promise.resolve({ ok: false })
})
vi.stubGlobal('fetch', mockFetch)

// ── Router ───────────────────────────────────────────────────────────────────

const mockRouter = createRouter({
  history: createMemoryHistory(),
  routes: [
    { path: '/parent', name: 'ParentChildrenListView', component: { template: '<div />' } },
    { path: '/notifications', name: 'NotificationView', component: { template: '<div />' } },
    { path: '/tasks', name: 'TaskView', component: { template: '<div />' } },
    { path: '/chores', name: 'ChoreView', component: { template: '<div />' } },
    { path: '/rewards', name: 'RewardView', component: { template: '<div />' } },
  ],
})

// ── Helpers ──────────────────────────────────────────────────────────────────

function mountLayout() {
  capturedChoreHandler = null
  capturedRewardHandler = null
  return mount(ParentLayout, {
    global: { plugins: [mockRouter] },
  })
}

function fireChoreConfirmation(operation: string) {
  capturedChoreHandler?.({ payload: { operation, child_id: 'c1', task_id: 't1' } })
}

function fireRewardRequest(operation: string) {
  capturedRewardHandler?.({ payload: { operation, child_id: 'c1', reward_id: 'r1' } })
}

// ── Tests ────────────────────────────────────────────────────────────────────

describe('ParentLayout – notification badge – chore confirmation handler', () => {
  beforeEach(async () => {
    vi.clearAllMocks()
    mockFetch.mockImplementation((url: string) => {
      if (url === '/api/pending-confirmations') {
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({ confirmations: [] }),
        })
      }
      return Promise.resolve({ ok: true, json: () => Promise.resolve({ version: '' }) })
    })
  })

  const refreshingOperations = ['CONFIRMED', 'APPROVED', 'REJECTED', 'CANCELLED', 'RESET']

  refreshingOperations.forEach((op) => {
    it(`refetches notification count on ${op} operation`, async () => {
      mountLayout()
      await flushPromises()
      const callsBefore = mockFetch.mock.calls.filter(
        (c) => c[0] === '/api/pending-confirmations',
      ).length

      fireChoreConfirmation(op)
      await flushPromises()

      const callsAfter = mockFetch.mock.calls.filter(
        (c) => c[0] === '/api/pending-confirmations',
      ).length
      expect(callsAfter).toBeGreaterThan(callsBefore)
    })
  })

  it('does not refetch on unknown operation', async () => {
    mountLayout()
    await flushPromises()
    const callsBefore = mockFetch.mock.calls.filter(
      (c) => c[0] === '/api/pending-confirmations',
    ).length

    fireChoreConfirmation('UNKNOWN_OP')
    await flushPromises()

    const callsAfter = mockFetch.mock.calls.filter(
      (c) => c[0] === '/api/pending-confirmations',
    ).length
    expect(callsAfter).toBe(callsBefore)
  })
})

describe('ParentLayout – notification badge – reward request handler', () => {
  beforeEach(async () => {
    vi.clearAllMocks()
    mockFetch.mockImplementation((url: string) => {
      if (url === '/api/pending-confirmations') {
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({ confirmations: [] }),
        })
      }
      return Promise.resolve({ ok: true, json: () => Promise.resolve({ version: '' }) })
    })
  })

  const refreshingOperations = ['CREATED', 'CANCELLED', 'GRANTED']

  refreshingOperations.forEach((op) => {
    it(`refetches notification count on ${op} operation`, async () => {
      mountLayout()
      await flushPromises()
      const callsBefore = mockFetch.mock.calls.filter(
        (c) => c[0] === '/api/pending-confirmations',
      ).length

      fireRewardRequest(op)
      await flushPromises()

      const callsAfter = mockFetch.mock.calls.filter(
        (c) => c[0] === '/api/pending-confirmations',
      ).length
      expect(callsAfter).toBeGreaterThan(callsBefore)
    })
  })
})
