import { http, HttpResponse } from 'msw'
import { test, expect } from './msw-setup'
import type { StoredEvent } from '../src/composables/useEventStorage'

const STORAGE_KEY = 'fete:events'

const fullEvent = {
  eventToken: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
  title: 'Summer BBQ',
  description: 'Bring your own drinks!',
  dateTime: '2026-03-15T20:00:00+01:00',
  timezone: 'Europe/Berlin',
  location: 'Central Park, NYC',
  attendeeCount: 12,
  cancelled: false,
}

const rsvpToken = 'd4e5f6a7-b8c9-0123-4567-890abcdef012'
const organizerToken = 'org-token-1234'

function seedEvents(events: StoredEvent[]): string {
  return `window.localStorage.setItem('${STORAGE_KEY}', ${JSON.stringify(JSON.stringify(events))})`
}

function watchSeed(): StoredEvent {
  return {
    eventToken: fullEvent.eventToken,
    title: fullEvent.title,
    dateTime: fullEvent.dateTime,
  }
}

function rsvpSeed(): StoredEvent {
  return {
    eventToken: fullEvent.eventToken,
    title: fullEvent.title,
    dateTime: fullEvent.dateTime,
    rsvpToken,
    rsvpName: 'Anna',
  }
}

function organizerSeed(): StoredEvent {
  return {
    eventToken: fullEvent.eventToken,
    title: fullEvent.title,
    dateTime: fullEvent.dateTime,
    organizerToken,
  }
}

test.describe('US1: Watch event from detail page', () => {
  test('bookmark unfilled by default, tapping watches the event', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.goto(`/events/${fullEvent.eventToken}`)

    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).toBeVisible()
    await expect(bookmark).toHaveAttribute('aria-label', 'Watch this event')

    await bookmark.click()

    await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')

    // Navigate to event list via back link
    await page.getByLabel('Back to home').click()

    // Event appears with "Watching" label
    await expect(page.getByText('Summer BBQ')).toBeVisible()
    await expect(page.getByText('Watching')).toBeVisible()
  })
})

test.describe('US2: Un-watch event from detail page', () => {
  test('tapping filled bookmark un-watches the event', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([watchSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')

    await bookmark.click()

    await expect(bookmark).toHaveAttribute('aria-label', 'Watch this event')

    // Navigate to event list via back link (avoid page.goto re-running addInitScript)
    await page.getByLabel('Back to home').click()

    // Event is gone
    await expect(page.getByText('Summer BBQ')).not.toBeVisible()
  })
})

test.describe('US3: Bookmark reflects attending status', () => {
  test('bookmark is not visible when user has RSVPed, list shows Attendee', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Bookmark not shown for attendees — RsvpBar shows status state
    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).not.toBeVisible()

    // Navigate to list via back link
    await page.getByLabel('Back to home').click()
    await expect(page.getByText('Attending')).toBeVisible()
    await expect(page.getByText('Watching')).not.toBeVisible()
  })
})

test.describe('US4: RSVP cancellation preserves watch status', () => {
  test('cancel RSVP → bookmark reappears, list shows Watching', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return new HttpResponse(null, { status: 204 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Cancel RSVP
    await page.getByRole('button', { name: /You're attending/ }).click()
    await page.locator('.rsvp-bar__cancel').click()
    await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()

    // Bookmark reappears in CTA state, filled because event is still stored
    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).toBeVisible()
    await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')

    // Navigate to list via back link
    await page.getByLabel('Back to home').click()
    await expect(page.getByText('Watching')).toBeVisible()
    await expect(page.getByText('Attending')).not.toBeVisible()
  })
})

test.describe('US5: No bookmark for attendees and organizers', () => {
  test('attendee does not see bookmark', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).not.toBeVisible()
  })

  test('organizer does not see bookmark', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([organizerSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).not.toBeVisible()
  })
})

test.describe('US6: Un-watch from event list', () => {
  test('deleting a watched event skips confirmation dialog', async ({ page }) => {
    await page.addInitScript(seedEvents([watchSeed()]))
    await page.goto('/')

    await expect(page.getByText('Summer BBQ')).toBeVisible()

    await page.getByRole('button', { name: /Remove Summer BBQ/ }).click()

    // No confirmation dialog — event removed immediately
    await expect(page.getByText('Remove event?')).not.toBeVisible()
    await expect(page.getByText('Summer BBQ')).not.toBeVisible()
  })
})

test.describe('US7: Watcher upgrades to attendee', () => {
  test('watch → RSVP → bookmark disappears, list shows Attendee', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
      http.post('*/api/events/:token/rsvps', () => {
        return HttpResponse.json(
          { rsvpToken: 'new-rsvp-token', name: 'Max' },
          { status: 201 },
        )
      }),
    )
    await page.addInitScript(seedEvents([watchSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Verify watching state — bookmark visible
    const bookmark = page.getByLabel(/watch.*this event/i)
    await expect(bookmark).toBeVisible()
    await expect(bookmark).toHaveAttribute('aria-label', 'Stop watching this event')

    // RSVP
    await page.getByRole('button', { name: "I'm attending" }).click()
    const dialog = page.getByRole('dialog', { name: 'RSVP' })
    await dialog.getByLabel('Your name').fill('Max')
    await dialog.getByRole('button', { name: 'Count me in' }).click()

    // Bookmark gone — status bar shown instead
    await expect(bookmark).not.toBeVisible()

    // Navigate to list via back link
    await page.getByLabel('Back to home').click()
    await expect(page.getByText('Attending')).toBeVisible()
    await expect(page.getByText('Watching')).not.toBeVisible()
  })
})
