// @vitest-environment jsdom
//
// The status page. We mock `@voltro/web` (the loader hook) + `@voltro/client`
// (the three subscriptions, keyed by tag) and assert: the loader drains the api,
// the SSR snapshot renders the banner/components/incidents, live subscription
// data overrides the snapshot, and the pure status math (banner + uptime) is
// correct on its own.

import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { act, createElement, type ReactNode } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { I18nProvider } from '@voltro/i18n'
import enCatalog from '../locales/en'
import { deriveOverall, uptimeGrid, uptimePercent, type Incident } from '../lib/status'

const loaderData = vi.fn<() => unknown>()
const subs = new Map<string, unknown>()
vi.mock('@voltro/web', () => ({ useLoaderData: () => loaderData() }))
vi.mock('@voltro/client', () => ({ useSubscription: (_api: string, tag: string) => ({ data: subs.get(tag) }) }))

const { default: StatusPage, meta, loader, renderMode } = await import('./page')

;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true

let container: HTMLDivElement
let root: Root

const render = (node: ReactNode): void => {
  container = document.createElement('div')
  document.body.appendChild(container)
  act(() => {
    root = createRoot(container)
    root.render(
      createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
    )
  })
}

const emptyData = { incidents: [], components: [], updates: [] }

beforeEach(() => {
  loaderData.mockReset()
  loaderData.mockReturnValue(emptyData)
  subs.clear()
})

afterEach(() => {
  if (root) act(() => root.unmount())
  container?.remove()
  document.body.innerHTML = ''
})

describe('status page — config + loader', () => {
  test('is an SSR page titled Status', () => {
    expect(renderMode).toBe('ssr')
    expect(meta({ locale: 'en' }).title).toBe('Status')
  })

  test('the loader drains all three feeds from the api', async () => {
    const query = vi.fn(async (tag: string) =>
      tag === 'incidents.live'  ? [{ id: 'inc_1' }]
      : tag === 'components.list' ? [{ id: 'cmp_1' }]
      : [{ id: 'iu_1' }])
    const data = await loader({ query } as never)
    expect(query).toHaveBeenCalledWith('incidents.live', {})
    expect(data.incidents).toHaveLength(1)
    expect(data.components).toHaveLength(1)
    expect(data.updates).toHaveLength(1)
  })

  test('returns empty feeds on a client navigation (no server query fn)', async () => {
    const data = await loader({ query: undefined } as never)
    expect(data).toEqual(emptyData)
  })
})

describe('status page — render', () => {
  test('shows the all-operational banner with no incidents', () => {
    render(createElement(StatusPage))
    expect(container.querySelector('.banner--operational')).not.toBeNull()
    expect(container.textContent).toContain('All systems operational')
  })

  test('renders a live incident over the (empty) SSR snapshot', () => {
    subs.set('incidents.live', [
      { id: 'inc_9', title: 'API degraded', impact: 'major', status: 'investigating', startedAt: '2026-08-01T00:00:00Z', resolvedAt: null },
    ])
    subs.set('updates.list', [
      { id: 'iu_1', incidentId: 'inc_9', body: 'Looking into it', status: 'investigating', createdAt: '2026-08-01T00:05:00Z' },
    ])
    render(createElement(StatusPage))
    expect(container.querySelector('.banner--degraded')).not.toBeNull()
    expect(container.textContent).toContain('API degraded')
    expect(container.querySelector('.timeline')).not.toBeNull()
    expect(container.textContent).toContain('Looking into it')
  })
})

describe('status math (pure)', () => {
  const inc = (over: Partial<Incident>): Incident => ({
    id: 'i', title: 't', impact: 'minor', status: 'investigating',
    startedAt: '2026-08-01T00:00:00Z', resolvedAt: null, ...over,
  })

  test('deriveOverall escalates with impact and clears when resolved', () => {
    expect(deriveOverall([], [])).toBe('operational')
    expect(deriveOverall([inc({ impact: 'major' })], [])).toBe('degraded')
    expect(deriveOverall([inc({ impact: 'critical' })], [])).toBe('major_outage')
    expect(deriveOverall([inc({ impact: 'critical', status: 'resolved', resolvedAt: '2026-08-02T00:00:00Z' })], [])).toBe('operational')
    expect(deriveOverall([], [{ id: 'c', name: 'API', status: 'major_outage' }])).toBe('major_outage')
  })

  test('uptimeGrid marks a day down only for a major/critical incident overlapping it', () => {
    const now = Date.parse('2026-08-10T12:00:00Z')
    const minorOnly = uptimeGrid([inc({ impact: 'minor', startedAt: '2026-08-09T00:00:00Z', resolvedAt: '2026-08-09T06:00:00Z' })], now, 90)
    expect(minorOnly.every(Boolean)).toBe(true)          // minor never dings uptime
    expect(uptimePercent(minorOnly)).toBe(100)

    const majorDay = uptimeGrid([inc({ impact: 'critical', startedAt: '2026-08-09T00:00:00Z', resolvedAt: '2026-08-09T06:00:00Z' })], now, 90)
    expect(majorDay.filter((up) => !up)).toHaveLength(1)  // exactly one down day
    expect(uptimePercent(majorDay)).toBeLessThan(100)
  })
})
