import { describe, it, expect, beforeEach } from 'vitest'
import { useEventStorage } from '../useEventStorage'

// jsdom provides a working localStorage in the window object
// but Node's --localstorage-file warning can be ignored
function clearStorage() {
  try {
    window.localStorage.setItem('fete:events', '[]')
  } catch {
    // Provide a minimal mock if localStorage is broken
    const store: Record<string, string> = {}
    Object.defineProperty(globalThis, 'localStorage', {
      value: {
        getItem: (key: string) => store[key] ?? null,
        setItem: (key: string, val: string) => {
          store[key] = val
        },
        removeItem: (key: string) => {
          delete store[key]
        },
      },
      writable: true,
      configurable: true,
    })
  }
}

describe('useEventStorage', () => {
  beforeEach(() => {
    clearStorage()
  })

  it('returns empty array when no events stored', () => {
    const { getStoredEvents } = useEventStorage()
    expect(getStoredEvents()).toEqual([])
  })

  it('saves and retrieves a created event', () => {
    const { saveCreatedEvent, getStoredEvents } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'abc-123',
      organizerToken: 'org-456',
      title: 'Birthday',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    const events = getStoredEvents()
    expect(events).toHaveLength(1)
    expect(events[0]!.eventToken).toBe('abc-123')
    expect(events[0]!.organizerToken).toBe('org-456')
    expect(events[0]!.title).toBe('Birthday')
  })

  it('returns organizer token for known event', () => {
    const { saveCreatedEvent, getOrganizerToken } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'abc-123',
      organizerToken: 'org-456',
      title: 'Test',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    expect(getOrganizerToken('abc-123')).toBe('org-456')
  })

  it('returns undefined organizer token for unknown event', () => {
    const { getOrganizerToken } = useEventStorage()
    expect(getOrganizerToken('unknown')).toBeUndefined()
  })

  it('stores multiple events independently', () => {
    const { saveCreatedEvent, getStoredEvents } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'event-1',
      title: 'First',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    saveCreatedEvent({
      eventToken: 'event-2',
      title: 'Second',
      dateTime: '2026-07-15T20:00:00+02:00',
    })

    const events = getStoredEvents()
    expect(events).toHaveLength(2)
    expect(events.map((e) => e.eventToken)).toContain('event-1')
    expect(events.map((e) => e.eventToken)).toContain('event-2')
  })

  it('overwrites event with same token', () => {
    const { saveCreatedEvent, getStoredEvents } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'abc-123',
      title: 'Old Title',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    saveCreatedEvent({
      eventToken: 'abc-123',
      title: 'New Title',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    const events = getStoredEvents()
    expect(events).toHaveLength(1)
    expect(events[0]!.title).toBe('New Title')
  })

  it('saves and retrieves RSVP for an existing event', () => {
    const { saveCreatedEvent, saveRsvp, getRsvp } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'abc-123',
      title: 'Birthday',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    saveRsvp('abc-123', 'rsvp-token-1', 'Max', 'Birthday', '2026-06-15T20:00:00+02:00')

    const rsvp = getRsvp('abc-123')
    expect(rsvp).toEqual({ rsvpToken: 'rsvp-token-1', rsvpName: 'Max' })
  })

  it('saves RSVP for a new event (not previously stored)', () => {
    const { saveRsvp, getRsvp, getStoredEvents } = useEventStorage()

    saveRsvp('new-event', 'rsvp-token-2', 'Anna', 'Party', '2026-08-01T18:00:00+02:00')

    const rsvp = getRsvp('new-event')
    expect(rsvp).toEqual({ rsvpToken: 'rsvp-token-2', rsvpName: 'Anna' })

    const events = getStoredEvents()
    expect(events).toHaveLength(1)
    expect(events[0]!.eventToken).toBe('new-event')
    expect(events[0]!.title).toBe('Party')
  })

  it('returns undefined RSVP for event without RSVP', () => {
    const { saveCreatedEvent, getRsvp } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'abc-123',
      title: 'Test',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    expect(getRsvp('abc-123')).toBeUndefined()
  })

  it('returns undefined RSVP for unknown event', () => {
    const { getRsvp } = useEventStorage()
    expect(getRsvp('unknown')).toBeUndefined()
  })

  it('removes an event by token', () => {
    const { saveCreatedEvent, getStoredEvents, removeEvent } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'event-1',
      title: 'First',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    saveCreatedEvent({
      eventToken: 'event-2',
      title: 'Second',
      dateTime: '2026-07-15T20:00:00+02:00',
    })

    removeEvent('event-1')

    const events = getStoredEvents()
    expect(events).toHaveLength(1)
    expect(events[0]!.eventToken).toBe('event-2')
  })

  it('removeEvent does nothing for unknown token', () => {
    const { saveCreatedEvent, getStoredEvents, removeEvent } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'event-1',
      title: 'First',
      dateTime: '2026-06-15T20:00:00+02:00',
    })

    removeEvent('nonexistent')

    expect(getStoredEvents()).toHaveLength(1)
  })
})

describe('useEventStorage – saveWatch / isStored', () => {
  beforeEach(() => {
    clearStorage()
  })

  it('saves a watch-only event (no rsvpToken, no organizerToken)', () => {
    const { saveWatch, getStoredEvents } = useEventStorage()

    saveWatch('watch-1', 'Concert', '2026-07-01T20:00:00+02:00')

    const events = getStoredEvents()
    expect(events).toHaveLength(1)
    expect(events[0]!.eventToken).toBe('watch-1')
    expect(events[0]!.title).toBe('Concert')
    expect(events[0]!.dateTime).toBe('2026-07-01T20:00:00+02:00')
    expect(events[0]!.rsvpToken).toBeUndefined()
    expect(events[0]!.organizerToken).toBeUndefined()
  })

  it('does not duplicate if event already stored', () => {
    const { saveWatch, saveRsvp, getStoredEvents } = useEventStorage()

    saveRsvp('evt-1', 'rsvp-1', 'Max', 'Party', '2026-07-01T20:00:00+02:00')
    saveWatch('evt-1', 'Party', '2026-07-01T20:00:00+02:00')

    expect(getStoredEvents()).toHaveLength(1)
    expect(getStoredEvents()[0]!.rsvpToken).toBe('rsvp-1')
  })

  it('isStored returns true for watched events', () => {
    const { saveWatch, isStored } = useEventStorage()

    saveWatch('watch-1', 'Concert', '2026-07-01T20:00:00+02:00')

    expect(isStored('watch-1')).toBe(true)
  })

  it('isStored returns true for attended events', () => {
    const { saveRsvp, isStored } = useEventStorage()

    saveRsvp('evt-1', 'rsvp-1', 'Max', 'Party', '2026-07-01T20:00:00+02:00')

    expect(isStored('evt-1')).toBe(true)
  })

  it('isStored returns true for organized events', () => {
    const { saveCreatedEvent, isStored } = useEventStorage()

    saveCreatedEvent({
      eventToken: 'evt-1',
      organizerToken: 'org-1',
      title: 'My Event',
      dateTime: '2026-07-01T20:00:00+02:00',
    })

    expect(isStored('evt-1')).toBe(true)
  })

  it('isStored returns false for unknown tokens', () => {
    const { isStored } = useEventStorage()

    expect(isStored('unknown')).toBe(false)
  })
})

describe('isValidStoredEvent', () => {
  // Import directly since it's an exported function
  let isValidStoredEvent: (e: unknown) => boolean

  beforeEach(async () => {
    const mod = await import('../useEventStorage')
    isValidStoredEvent = mod.isValidStoredEvent
  })

  it('returns true for a valid event', () => {
    expect(
      isValidStoredEvent({
        eventToken: 'abc-123',
        title: 'Birthday',
        dateTime: '2026-06-15T20:00:00+02:00',
        }),
    ).toBe(true)
  })

  it('returns false for null', () => {
    expect(isValidStoredEvent(null)).toBe(false)
  })

  it('returns false for non-object', () => {
    expect(isValidStoredEvent('string')).toBe(false)
  })

  it('returns false when eventToken is missing', () => {
    expect(
      isValidStoredEvent({
        title: 'Birthday',
        dateTime: '2026-06-15T20:00:00+02:00',
      }),
    ).toBe(false)
  })

  it('returns false when eventToken is empty', () => {
    expect(
      isValidStoredEvent({
        eventToken: '',
        title: 'Birthday',
        dateTime: '2026-06-15T20:00:00+02:00',
      }),
    ).toBe(false)
  })

  it('returns false when title is missing', () => {
    expect(
      isValidStoredEvent({
        eventToken: 'abc-123',
        dateTime: '2026-06-15T20:00:00+02:00',
      }),
    ).toBe(false)
  })

  it('returns false when dateTime is invalid', () => {
    expect(
      isValidStoredEvent({
        eventToken: 'abc-123',
        title: 'Birthday',
        dateTime: 'not-a-date',
      }),
    ).toBe(false)
  })

  it('returns false when dateTime is empty', () => {
    expect(
      isValidStoredEvent({
        eventToken: 'abc-123',
        title: 'Birthday',
        dateTime: '',
      }),
    ).toBe(false)
  })
})
