import { render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, test } from 'vitest'
import { WidgetError } from './error'
import { useWidgetStore } from '../stores/widget-store'

describe('WidgetError', () => {
  const widgetId = 'test-error-widget'

  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
  })

  describe('when error exists', () => {
    test('renders Error UI with default title and message when error is empty object', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: {},
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Error')).toBeTruthy()
      expect(
        screen.getByText(
          'An error occurred while loading the widget. Please try again.',
        ),
      ).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })

    test('renders custom title with default message', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: { title: 'Database Connection Failed' },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Database Connection Failed')).toBeTruthy()
      expect(
        screen.getByText(
          'An error occurred while loading the widget. Please try again.',
        ),
      ).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })

    test('renders default title with custom message', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: { message: 'The server returned a 500 error.' },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Error')).toBeTruthy()
      expect(screen.getByText('The server returned a 500 error.')).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })

    test('renders both custom title and message', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: {
          title: 'Network Error',
          message:
            'Unable to connect to the API. Check your internet connection.',
        },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Network Error')).toBeTruthy()
      expect(
        screen.getByText(
          'Unable to connect to the API. Check your internet connection.',
        ),
      ).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })

    test('uses defaults when title and message are empty strings', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: {
          title: 'Error',
          message:
            'An error occurred while loading the widget. Please try again.',
        },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Error')).toBeTruthy()
      expect(
        screen.getByText(
          'An error occurred while loading the widget. Please try again.',
        ),
      ).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })
  })

  describe('when no error exists', () => {
    test('renders children when error is undefined', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: undefined,
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Error')).toBeNull()
    })

    test('renders children when widget has no error property', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Error')).toBeNull()
    })
  })

  describe('loading states', () => {
    test('renders children when isLoading is true, even with error', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: true,
        isFetching: false,
        error: { title: 'Some error' },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Error')).toBeNull()
    })

    test('renders children when isFetching is true, even with error', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: true,
        error: { title: 'Some error' },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Error')).toBeNull()
    })

    test('renders children when both isLoading and isFetching are true, even with error', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: true,
        isFetching: true,
        error: { title: 'Some error' },
      })

      render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Error')).toBeNull()
    })
  })

  describe('reactivity', () => {
    test('updates when error appears', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: undefined,
      })

      const { rerender } = render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()

      // Add error
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: { title: 'Failed to load' },
      })

      rerender(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Failed to load')).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()
    })

    test('updates when error clears', () => {
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: { title: 'Failed to load' },
      })

      const { rerender } = render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Failed to load')).toBeTruthy()

      // Clear error
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: undefined,
      })

      rerender(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Failed to load')).toBeNull()
    })

    test('transitions from loading to error to success', () => {
      // Start loading
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: true,
        isFetching: false,
        error: undefined,
      })

      const { rerender } = render(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()

      // Error occurs
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: { title: 'Network error' },
      })

      rerender(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Network error')).toBeTruthy()
      expect(screen.queryByText('Widget Content')).toBeNull()

      // Error clears on retry
      useWidgetStore.getState().setWidget(widgetId, {
        isLoading: false,
        isFetching: false,
        error: undefined,
      })

      rerender(
        <WidgetError id={widgetId}>
          <div>Widget Content</div>
        </WidgetError>,
      )

      expect(screen.getByText('Widget Content')).toBeTruthy()
      expect(screen.queryByText('Network error')).toBeNull()
    })
  })
})
