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

const STORAGE_KEY = 'fete:events'

const futureEvent1: StoredEvent = {
  eventToken: 'future-aaa',
  title: 'Summer BBQ',
  dateTime: '2027-06-15T18:00:00Z',
  organizerToken: 'org-token-1',
}

const futureEvent2: StoredEvent = {
  eventToken: 'future-bbb',
  title: 'Team Meeting',
  dateTime: '2027-01-10T09:00:00Z',
  rsvpToken: 'rsvp-token-1',
  rsvpName: 'Alice',
}

const pastEvent: StoredEvent = {
  eventToken: 'past-ccc',
  title: 'New Year Party',
  dateTime: '2025-01-01T00:00:00Z',
}

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

test.describe('US2: Empty State', () => {
  test('shows empty state when no events are stored', async ({ page }) => {
    await page.goto('/')

    await expect(page.getByText('No events yet')).toBeVisible()
    await expect(page.getByRole('link', { name: /Create Event/ })).toBeVisible()
  })

  test('empty state links to create page', async ({ page }) => {
    await page.goto('/')

    const link = page.getByRole('link', { name: /Create Event/ })
    await expect(link).toHaveAttribute('href', '/create')
  })

  test('empty state is hidden when events exist', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    await expect(page.getByText('No events yet')).not.toBeVisible()
  })
})

test.describe('US4: Past Events Appear Faded', () => {
  test('past events have the faded modifier class', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1, pastEvent]))
    await page.goto('/')

    const cards = page.locator('.event-card')
    await expect(cards).toHaveCount(2)

    // Future event should NOT have past class
    const futureCard = cards.filter({ hasText: 'Summer BBQ' })
    await expect(futureCard).not.toHaveClass(/event-card--past/)

    // Past event should have past class
    const pastCard = cards.filter({ hasText: 'New Year Party' })
    await expect(pastCard).toHaveClass(/event-card--past/)
  })

  test('past events remain clickable', async ({ page, network }) => {
    await page.addInitScript(seedEvents([pastEvent]))

    const { http, HttpResponse } = await import('msw')
    network.use(
      http.get('*/api/events/:token', () => {
        return HttpResponse.json({
          eventToken: pastEvent.eventToken,
          title: pastEvent.title,
          dateTime: pastEvent.dateTime,
          description: '',
          location: '',
          timezone: 'UTC',
          attendeeCount: 0,
        })
      }),
    )

    await page.goto('/')
    await page.getByText('New Year Party').click()
    await expect(page).toHaveURL(`/events/${pastEvent.eventToken}`)
  })
})

test.describe('US3: Remove Event from List', () => {
  test('delete icon triggers confirmation dialog, confirm removes event', async ({
    page,
    network,
  }) => {
    await page.addInitScript(seedEvents([futureEvent1, futureEvent2]))

    const { http, HttpResponse } = await import('msw')
    network.use(
      http.patch('*/api/events/:token', () => {
        return new HttpResponse(null, { status: 204 })
      }),
    )

    await page.goto('/')

    // Both events visible
    await expect(page.getByText('Summer BBQ')).toBeVisible()
    await expect(page.getByText('Team Meeting')).toBeVisible()

    // Click delete on Summer BBQ (organizer event)
    await page.getByRole('button', { name: /Remove Summer BBQ/ }).click()

    // Confirmation dialog appears (organizer event shows "Cancel event?")
    await expect(page.getByText('Cancel event?')).toBeVisible()

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

    // Event is gone, other remains
    await expect(page.getByText('Summer BBQ')).not.toBeVisible()
    await expect(page.getByText('Team Meeting')).toBeVisible()
  })

  test('cancel keeps the event in the list', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    await page.getByRole('button', { name: /Remove Summer BBQ/ }).click()
    await expect(page.getByText('Cancel event?')).toBeVisible()

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

    // Dialog gone, event still there
    await expect(page.getByText('Cancel event?')).not.toBeVisible()
    await expect(page.getByText('Summer BBQ')).toBeVisible()
  })
})

test.describe('US5: Visual Distinction for Event Roles', () => {
  test('shows organizer badge for events with organizerToken', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    const card = page.locator('.event-card').filter({ hasText: 'Summer BBQ' })
    const badge = card.locator('.event-card__badge')
    await expect(badge).toBeVisible()
    await expect(badge).toHaveText('Organizing')
    await expect(badge).toHaveClass(/event-card__badge--organizer/)
  })

  test('shows attendee badge for events with rsvpToken only', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent2]))
    await page.goto('/')

    const card = page.locator('.event-card').filter({ hasText: 'Team Meeting' })
    const badge = card.locator('.event-card__badge')
    await expect(badge).toBeVisible()
    await expect(badge).toHaveText('Attending')
    await expect(badge).toHaveClass(/event-card__badge--attendee/)
  })

  test('shows watcher badge for events without organizerToken or rsvpToken', async ({ page }) => {
    await page.addInitScript(seedEvents([pastEvent]))
    await page.goto('/')

    const card = page.locator('.event-card').filter({ hasText: 'New Year Party' })
    const badge = card.locator('.event-card__badge')
    await expect(badge).toBeVisible()
    await expect(badge).toHaveText('Watching')
    await expect(badge).toHaveClass(/event-card__badge--watcher/)
  })
})

test.describe('FAB: Create Event Button', () => {
  test('FAB is visible when events exist', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    const fab = page.getByRole('link', { name: 'Create event' })
    await expect(fab).toBeVisible()
  })

  test('FAB navigates to create page', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    const fab = page.getByRole('link', { name: 'Create event' })
    await expect(fab).toHaveAttribute('href', '/create')
  })

  test('FAB is not visible on empty state (empty state has its own CTA)', async ({ page }) => {
    await page.goto('/')

    await expect(page.locator('.fab')).toHaveCount(0)
  })
})

test.describe('Temporal Grouping: Section Headers', () => {
  test('events are distributed under correct section headers', async ({ page }) => {
    // Use dates relative to "now" to ensure correct section assignment
    const now = new Date()
    const todayEvent: StoredEvent = {
      eventToken: 'today-1',
      title: 'Today Standup',
      dateTime: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 18, 0, 0).toISOString(),
    }
    const laterEvent: StoredEvent = {
      eventToken: 'later-1',
      title: 'Future Conference',
      dateTime: new Date(now.getFullYear() + 1, 0, 15, 10, 0, 0).toISOString(),
    }
    await page.addInitScript(seedEvents([todayEvent, laterEvent, pastEvent]))
    await page.goto('/')

    // Verify section headers appear
    await expect(page.getByRole('heading', { name: 'Today', level: 2 })).toBeVisible()
    await expect(page.getByRole('heading', { name: 'Later', level: 2 })).toBeVisible()
    await expect(page.getByRole('heading', { name: 'Past', level: 2 })).toBeVisible()

    // Events are in the correct sections
    const sections = page.locator('.event-section')
    const todaySection = sections.filter({ has: page.getByRole('heading', { name: 'Today', level: 2 }) })
    await expect(todaySection.getByText('Today Standup')).toBeVisible()

    const laterSection = sections.filter({ has: page.getByRole('heading', { name: 'Later', level: 2 }) })
    await expect(laterSection.getByText('Future Conference')).toBeVisible()

    const pastSection = sections.filter({ has: page.getByRole('heading', { name: 'Past', level: 2 }) })
    await expect(pastSection.getByText('New Year Party')).toBeVisible()
  })

  test('empty sections are not rendered', async ({ page }) => {
    // Only a past event — no Today, This Week, or Later sections
    await page.addInitScript(seedEvents([pastEvent]))
    await page.goto('/')

    await expect(page.getByRole('heading', { name: 'Past', level: 2 })).toBeVisible()
    await expect(page.getByRole('heading', { name: 'Today', level: 2 })).toHaveCount(0)
    await expect(page.getByRole('heading', { name: 'This Week', level: 2 })).toHaveCount(0)
    await expect(page.getByRole('heading', { name: 'Next Week', level: 2 })).toHaveCount(0)
    await expect(page.getByRole('heading', { name: 'Later', level: 2 })).toHaveCount(0)
  })

  test('Today section header has emphasis CSS class', async ({ page }) => {
    const now = new Date()
    const todayEvent: StoredEvent = {
      eventToken: 'today-emph',
      title: 'Emphasis Test',
      dateTime: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 20, 0, 0).toISOString(),
    }
    await page.addInitScript(seedEvents([todayEvent]))
    await page.goto('/')

    const todayHeader = page.getByRole('heading', { name: 'Today', level: 2 })
    await expect(todayHeader).toHaveClass(/section-header--emphasized/)
  })
})

test.describe('Temporal Grouping: Date Subheaders', () => {
  test('no date subheader in Today section', async ({ page }) => {
    const now = new Date()
    const todayEvent: StoredEvent = {
      eventToken: 'today-sub',
      title: 'No Subheader Test',
      dateTime: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 19, 0, 0).toISOString(),
    }
    await page.addInitScript(seedEvents([todayEvent]))
    await page.goto('/')

    const todaySection = page.locator('.event-section').filter({
      has: page.getByRole('heading', { name: 'Today', level: 2 }),
    })
    await expect(todaySection.locator('.date-subheader')).toHaveCount(0)
  })

  test('date subheaders appear in Later section', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1, futureEvent2]))
    await page.goto('/')

    const laterSection = page.locator('.event-section').filter({
      has: page.getByRole('heading', { name: 'Later', level: 2 }),
    })
    // Both future events are on different dates, so expect subheaders
    const subheaders = laterSection.locator('.date-subheader')
    await expect(subheaders).toHaveCount(2)
  })

  test('date subheaders appear in Past section', async ({ page }) => {
    await page.addInitScript(seedEvents([pastEvent]))
    await page.goto('/')

    const pastSection = page.locator('.event-section').filter({
      has: page.getByRole('heading', { name: 'Past', level: 2 }),
    })
    await expect(pastSection.locator('.date-subheader')).toHaveCount(1)
  })
})

test.describe('Temporal Grouping: Time Display', () => {
  test('future event cards show clock time', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    const timeLabel = page.locator('.event-card__time')
    const text = await timeLabel.first().textContent()
    // Should show clock time (e.g., "18:00" or "6:00 PM"), not relative time
    expect(text).toMatch(/\d{1,2}[:.]\d{2}/)
  })

  test('past event cards show relative time', async ({ page }) => {
    await page.addInitScript(seedEvents([pastEvent]))
    await page.goto('/')

    const timeLabel = page.locator('.event-card__time')
    const text = await timeLabel.first().textContent()
    // Should show relative time like "X years ago" or "last year"
    expect(text).toMatch(/ago|last|yesterday/)
  })
})

test.describe('US1: View My Events', () => {
  test('displays all stored events with title and relative time', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1, futureEvent2, pastEvent]))
    await page.goto('/')

    await expect(page.getByText('Summer BBQ')).toBeVisible()
    await expect(page.getByText('Team Meeting')).toBeVisible()
    await expect(page.getByText('New Year Party')).toBeVisible()
  })

  test('events are sorted: upcoming ascending, then past', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1, futureEvent2, pastEvent]))
    await page.goto('/')

    const titles = page.locator('.event-card__title')
    await expect(titles).toHaveCount(3)
    // Team Meeting (Jan 2027) before Summer BBQ (Jun 2027), then past event
    await expect(titles.nth(0)).toHaveText('Team Meeting')
    await expect(titles.nth(1)).toHaveText('Summer BBQ')
    await expect(titles.nth(2)).toHaveText('New Year Party')
  })

  test('clicking an event navigates to its detail page', async ({ page, network }) => {
    await page.addInitScript(seedEvents([futureEvent1]))

    // Mock the event detail API so navigation doesn't fail
    const { http, HttpResponse } = await import('msw')
    network.use(
      http.get('*/api/events/:token', () => {
        return HttpResponse.json({
          eventToken: futureEvent1.eventToken,
          title: futureEvent1.title,
          dateTime: futureEvent1.dateTime,
          description: '',
          location: '',
          timezone: 'UTC',
          attendeeCount: 0,
        })
      }),
    )

    await page.goto('/')
    await page.getByText('Summer BBQ').click()
    await expect(page).toHaveURL(`/events/${futureEvent1.eventToken}`)
  })

  test('each event shows a relative time label', async ({ page }) => {
    await page.addInitScript(seedEvents([futureEvent1]))
    await page.goto('/')

    // The relative time element should exist and contain text (exact value depends on current time)
    const timeLabel = page.locator('.event-card__time')
    await expect(timeLabel).toHaveCount(1)
    await expect(timeLabel.first()).not.toBeEmpty()
  })
})
