/**
 * Tests for Resource component - resource.tsx
 *
 * TDD RED phase: Write failing tests first.
 *
 * This includes tests for the stale registration bug (ui-n710):
 * Resource component uses useEffect with only [name] dependency,
 * so changing view components after mount doesn't update the registry.
 */

import { describe, it, expect } from 'vitest'
import { render, screen, act } from '@testing-library/react'
import { useState, type FC } from 'react'
import { Resource } from '../../components/resource'
import { ResourcesProvider, useResources, type ResourcesContextValue } from '../../context/resource-context'
import type { Identifier } from '../../types'

// Mock view components
const MockListComponent: FC = () => <div>List</div>
const UpdatedEditComponent: FC<{ id: Identifier }> = ({ id }) => <div>Updated Edit {id}</div>

// Helper to access resources context
function ResourcesInspector({ onResources }: { onResources: (ctx: ResourcesContextValue) => void }) {
  const ctx = useResources()
  onResources(ctx)
  return null
}

describe('Resource Component', () => {
  describe('basic registration', () => {
    it('should register resource with ResourcesProvider on mount', () => {
      let ctx: ResourcesContextValue | undefined

      render(
        <ResourcesProvider>
          <Resource name="users" label="Users" list={MockListComponent} />
          <ResourcesInspector onResources={(c) => { ctx = c }} />
        </ResourcesProvider>
      )

      const resource = ctx!.getResource('users')
      expect(resource).toBeDefined()
      expect(resource?.name).toBe('users')
      expect(resource?.label).toBe('Users')
      expect(resource?.list).toBe(MockListComponent)
    })

    it('should unregister resource on unmount', () => {
      let ctx: ResourcesContextValue | undefined

      const { unmount } = render(
        <ResourcesProvider>
          <Resource name="users" label="Users" />
          <ResourcesInspector onResources={(c) => { ctx = c }} />
        </ResourcesProvider>
      )

      expect(ctx!.getResource('users')).toBeDefined()

      unmount()

      // After unmount, the resource should be unregistered
      // Note: We need to re-render the inspector to see the change
      // This is tricky to test because unmount removes everything
    })

    it('should re-register when name changes', () => {
      let ctx: ResourcesContextValue | undefined

      function DynamicResource() {
        const [name, setName] = useState('users')

        return (
          <ResourcesProvider>
            <Resource name={name} label={`${name} label`} />
            <ResourcesInspector onResources={(c) => { ctx = c }} />
            <button onClick={() => setName('products')} data-testid="change-name">
              Change Name
            </button>
          </ResourcesProvider>
        )
      }

      render(<DynamicResource />)

      expect(ctx!.getResource('users')).toBeDefined()
      expect(ctx!.getResource('products')).toBeUndefined()

      act(() => {
        screen.getByTestId('change-name').click()
      })

      // Old resource should be unregistered, new one registered
      expect(ctx!.getResource('users')).toBeUndefined()
      expect(ctx!.getResource('products')).toBeDefined()
    })
  })

  describe('stale registration bug (ui-n710)', () => {
    /**
     * This test demonstrates the stale registration bug:
     *
     * When view components (list, edit, etc.) change but name stays the same,
     * the registry doesn't get updated because useEffect only depends on [name].
     *
     * Current behavior: The registry keeps the OLD definition
     * Expected behavior: The registry should have the UPDATED definition
     */
    it('should update registry when view components change (currently FAILING due to stale registration)', () => {
      let ctx: ResourcesContextValue | undefined

      function DynamicResource() {
        const [editComponent, setEditComponent] = useState<FC<{ id: Identifier }> | undefined>(undefined)

        return (
          <ResourcesProvider>
            <Resource
              name="users"
              label="Users"
              list={MockListComponent}
              edit={editComponent}
            />
            <ResourcesInspector onResources={(c) => { ctx = c }} />
            <button onClick={() => setEditComponent(() => UpdatedEditComponent)} data-testid="add-edit">
              Add Edit
            </button>
          </ResourcesProvider>
        )
      }

      render(<DynamicResource />)

      // Initially no edit component
      expect(ctx!.getResource('users')?.edit).toBeUndefined()
      expect(ctx!.getResource('users')?.list).toBe(MockListComponent)

      // Add edit component - the Resource's props change but name stays the same
      act(() => {
        screen.getByTestId('add-edit').click()
      })

      // BUG: This assertion will FAIL because useEffect only runs when name changes
      // The registry still has the OLD definition without the edit component
      //
      // Expected: UpdatedEditComponent
      // Actual: undefined (stale definition)
      expect(ctx!.getResource('users')?.edit).toBe(UpdatedEditComponent)
    })

    it('should update registry when label changes', () => {
      let ctx: ResourcesContextValue | undefined

      function DynamicResource() {
        const [label, setLabel] = useState('Users')

        return (
          <ResourcesProvider>
            <Resource name="users" label={label} />
            <ResourcesInspector onResources={(c) => { ctx = c }} />
            <button onClick={() => setLabel('Updated Users')} data-testid="change-label">
              Change Label
            </button>
          </ResourcesProvider>
        )
      }

      render(<DynamicResource />)

      expect(ctx!.getResource('users')?.label).toBe('Users')

      act(() => {
        screen.getByTestId('change-label').click()
      })

      // BUG: This will also fail due to stale registration
      expect(ctx!.getResource('users')?.label).toBe('Updated Users')
    })
  })

  describe('children rendering', () => {
    it('should render children wrapped in ResourceProvider when provided', () => {
      render(
        <ResourcesProvider>
          <Resource name="users" label="Users">
            <div data-testid="child-content">Child Content</div>
          </Resource>
        </ResourcesProvider>
      )

      expect(screen.getByTestId('child-content').textContent).toBe('Child Content')
    })

    it('should not render anything when no children provided', () => {
      const { container } = render(
        <ResourcesProvider>
          <Resource name="users" label="Users" />
        </ResourcesProvider>
      )

      // Resource returns null when no children
      expect(container.querySelector('[data-testid]')).toBeNull()
    })
  })
})
