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,
}

const rsvpToken = 'd4e5f6a7-b8c9-0123-4567-890abcdef012'

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

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

test.describe('US1: Cancel RSVP from Event Detail View', () => {
  test('status bar shows cancel affordance when RSVP\'d', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Status bar visible
    const statusBar = page.getByRole('button', { name: /You're attending/ })
    await expect(statusBar).toBeVisible()

    // Cancel button hidden initially
    await expect(page.getByRole('button', { name: 'Cancel RSVP' })).not.toBeVisible()
  })

  test('tapping status bar reveals cancel button', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Tap status bar
    await page.getByRole('button', { name: /You're attending/ }).click()

    // Cancel button appears
    await expect(page.getByRole('button', { name: 'Cancel RSVP' })).toBeVisible()
  })

  test('confirm cancellation → localStorage cleared, count decremented, bar reset', 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}`)

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

    // Confirm dialog
    await expect(page.getByText('The organizer will no longer see you as attending.')).toBeVisible()
    await page.getByRole('alertdialog').getByRole('button', { name: 'Cancel RSVP' }).click()

    // Bar resets to CTA state
    await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()
    await expect(page.getByText("You're attending!")).not.toBeVisible()

    // Attendee count decremented
    await expect(page.getByText('11 going')).toBeVisible()

    // localStorage cleared
    const stored = await page.evaluate(() => {
      const raw = localStorage.getItem('fete:events')
      return raw ? JSON.parse(raw) : null
    })
    const event = stored?.find((e: StoredEvent) => e.eventToken === fullEvent.eventToken)
    expect(event?.rsvpToken).toBeUndefined()
    expect(event?.rsvpName).toBeUndefined()
  })

  test('server error → error message, state unchanged', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return HttpResponse.json({ error: 'fail' }, { status: 500 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Expand → Cancel → Confirm in dialog
    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()

    // Error message
    await expect(page.getByText('Could not cancel RSVP. Please try again.')).toBeVisible()

    // Attendee count unchanged
    await expect(page.getByText('12 going')).toBeVisible()
  })

  test('re-RSVP after cancel works', 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 })
      }),
      http.post('*/api/events/:token/rsvps', () => {
        return HttpResponse.json(
          { rsvpToken: 'new-rsvp-token', name: 'Max' },
          { status: 201 },
        )
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Cancel first
    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()

    // CTA should be back
    await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()

    // Re-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()

    // Status bar returns
    await expect(page.getByText("You're attending!")).toBeVisible()
  })
})

test.describe('US2: Auto-Cancel on Event List Removal', () => {
  test('removal of RSVP\'d event shows attendance warning in dialog', async ({ page }) => {
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto('/')

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

    await expect(page.getByText('your attendance will be cancelled')).toBeVisible()
  })

  test('removal of non-RSVP\'d watcher event shows standard dialog', async ({ page }) => {
    const watcherEvent: StoredEvent = {
      eventToken: 'watcher-token',
      title: 'Watcher Event',
      dateTime: '2027-06-15T18:00:00Z',
    }
    await page.addInitScript(seedEvents([watcherEvent]))
    await page.goto('/')

    // Watcher events are removed directly without dialog
    await page.getByRole('button', { name: /Remove Watcher Event/ }).click()

    // Watcher removal is immediate — event disappears
    await expect(page.getByText('Watcher Event')).not.toBeVisible()
  })

  test('confirm removal → DELETE called → event removed from list', async ({ page, network }) => {
    network.use(
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return new HttpResponse(null, { status: 204 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto('/')

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

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

    // localStorage updated
    const stored = await page.evaluate(() => {
      const raw = localStorage.getItem('fete:events')
      return raw ? JSON.parse(raw) : null
    })
    const found = stored?.find((e: StoredEvent) => e.eventToken === fullEvent.eventToken)
    expect(found).toBeUndefined()
  })

  test('server error on DELETE → error message, event stays in list', async ({ page, network }) => {
    network.use(
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return HttpResponse.json({ error: 'fail' }, { status: 500 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto('/')

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

    // Event still in list
    await expect(page.getByText('Summer BBQ')).toBeVisible()
  })

  test('dismiss dialog → no changes', async ({ page }) => {
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto('/')

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

    // Event still there
    await expect(page.getByText('Summer BBQ')).toBeVisible()
  })
})

test.describe('US3: Cancel RSVP with Stale/Invalid Token', () => {
  test('cancel from detail view with stale token (404) → treated as success', async ({ page, network }) => {
    network.use(
      http.get('*/api/events/:token', () => HttpResponse.json(fullEvent)),
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return HttpResponse.json({ error: 'not found' }, { status: 404 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto(`/events/${fullEvent.eventToken}`)

    // Cancel flow
    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()

    // Treated as success — CTA returns
    await expect(page.getByRole('button', { name: "I'm attending" })).toBeVisible()

    // localStorage cleaned
    const stored = await page.evaluate(() => {
      const raw = localStorage.getItem('fete:events')
      return raw ? JSON.parse(raw) : null
    })
    const event = stored?.find((e: StoredEvent) => e.eventToken === fullEvent.eventToken)
    expect(event?.rsvpToken).toBeUndefined()
  })

  test('event list removal with stale token (404) → treated as success', async ({ page, network }) => {
    network.use(
      http.delete('*/api/events/:token/rsvps/:rsvpToken', () => {
        return HttpResponse.json({ error: 'not found' }, { status: 404 })
      }),
    )
    await page.addInitScript(seedEvents([rsvpSeed()]))
    await page.goto('/')

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

    // Event removed from list
    await expect(page.getByText('Summer BBQ')).not.toBeVisible()
  })
})
