import { render, screen } from '@testing-library/react'
import { http, HttpResponse } from 'msw'
import { MemoryRouter, Route, Routes } from 'react-router'
import { describe, expect, it } from 'vitest'
import { AuthProvider } from '../auth/AuthProvider'
import { server } from '../test/server'
import ScenarioShowPage from './ScenarioShowPage'

const SCENARIO_ID = '11111111-1111-1111-1111-111111111111'

/**
 * ScenarioShowPage renders under AuthProvider (same /api/me probe as every
 * authed page) plus a minimal own route harness carrying the `:id` param —
 * the real routes.tsx wiring is a separate test (14), so this page test does
 * not depend on it.
 */
function renderPage() {
  render(
    <MemoryRouter initialEntries={[`/scenarios/${SCENARIO_ID}`]}>
      <AuthProvider>
        <Routes>
          <Route path="/scenarios/:id" element={<ScenarioShowPage />} />
        </Routes>
      </AuthProvider>
    </MemoryRouter>,
  )
}

describe('ScenarioShowPage', () => {
  it('renders each embedded bucket with its name, type, allocation and priority', async () => {
    server.use(
      http.get('http://localhost/api/me', () =>
        HttpResponse.json({ id: 'u1', email: 'a@b.com' }),
      ),
      http.get(`http://localhost/api/scenarios/${SCENARIO_ID}`, () =>
        HttpResponse.json({
          '@context': '/api/contexts/Scenario',
          '@id': `/api/scenarios/${SCENARIO_ID}`,
          '@type': 'Scenario',
          name: 'Emergency Fund',
          description: 'Rainy day savings',
          buckets: [
            {
              '@id': '/api/buckets/22222222-2222-2222-2222-222222222222',
              '@type': 'Bucket',
              name: 'Rent',
              type: 'need',
              priority: 1,
              sortOrder: 0,
              allocationType: 'fixed_limit',
              allocationValue: 10000,
              startingAmount: 3000,
              bufferMultiplier: '0.00',
            },
            {
              '@id': '/api/buckets/33333333-3333-3333-3333-333333333333',
              '@type': 'Bucket',
              name: 'Dining Out',
              type: 'want',
              priority: 2,
              sortOrder: 1,
              allocationType: 'percentage',
              allocationValue: 2500,
              startingAmount: 1200,
              bufferMultiplier: '0.00',
            },
          ],
        }),
      ),
      // Deliberately NOT stubbing /api/buckets — MSW's onUnhandledRequest:
      // 'error' fails this test if the page ever issues a second fetch,
      // enforcing the single-GET-with-embedded-buckets contract.
    )

    renderPage()

    expect(await screen.findByText('Rent')).toBeInTheDocument()
    expect(screen.getByText('Dining Out')).toBeInTheDocument()

    expect(screen.getByText(/need/i)).toBeInTheDocument()
    expect(screen.getByText(/want/i)).toBeInTheDocument()

    // Allocation: formatted per the locked display contract — fixed_limit is
    // dollars-with-cents from CENTS (10000 -> '$100.00'), percentage is
    // percent from BASIS POINTS (2500 -> '25%').
    expect(screen.getByText('$100.00')).toBeInTheDocument()
    expect(screen.getByText('25%')).toBeInTheDocument()

    // Priority: assert each bucket's own priority is shown somewhere within
    // its own rendered content, rather than a page-wide loose number match
    // (which could coincidentally match allocation/other digits instead).
    const rentPriorityMarker = await screen.findByText((_, element) =>
      element?.textContent === 'Priority 1',
    )
    const diningPriorityMarker = await screen.findByText((_, element) =>
      element?.textContent === 'Priority 2',
    )
    expect(rentPriorityMarker).toBeInTheDocument()
    expect(diningPriorityMarker).toBeInTheDocument()
  })

  it('renders a distinct not-found state when the scenario 404s (e.g. not owned)', async () => {
    server.use(
      http.get('http://localhost/api/me', () =>
        HttpResponse.json({ id: 'u1', email: 'a@b.com' }),
      ),
      http.get(`http://localhost/api/scenarios/${SCENARIO_ID}`, () =>
        HttpResponse.json({ message: 'Not Found' }, { status: 404 }),
      ),
    )

    renderPage()

    expect(await screen.findByText(/not found/i)).toBeInTheDocument()
    expect(
      screen.queryByText(/could not load this scenario/i),
    ).not.toBeInTheDocument()

    // Lock in the accessibility semantics distinction from the error state
    // (role="alert") — a copy-paste that swaps this to "alert" should fail
    // here even if the visible copy still says "not found".
    expect(await screen.findByRole('status')).toHaveTextContent(/not found/i)
  })

  it('renders the generic error state for a non-404 failure', async () => {
    server.use(
      http.get('http://localhost/api/me', () =>
        HttpResponse.json({ id: 'u1', email: 'a@b.com' }),
      ),
      http.get(`http://localhost/api/scenarios/${SCENARIO_ID}`, () =>
        HttpResponse.json({ message: 'Internal Server Error' }, { status: 500 }),
      ),
    )

    renderPage()

    expect(await screen.findByRole('alert')).toHaveTextContent(
      /could not load this scenario/i,
    )
  })
})
