import { cleanup, render, screen } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import userEvent from '@testing-library/user-event'
import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ROUTER_FUTURE_FLAGS } from '../router/router-future'

const mockUsePlatformAuth = vi.fn()
const mockLogout = vi.fn()
const mockToggleColorMode = vi.fn()
const mockGetAuthHealth = vi.fn()
const mockGetReleaseManifest = vi.fn()

vi.mock('../auth/platform-auth', () => ({
  usePlatformAuth: () => mockUsePlatformAuth(),
}))

vi.mock('../auth/auth-api', () => ({
  getAuthHealth: (...args: unknown[]) => mockGetAuthHealth(...args),
  getReleaseManifest: (...args: unknown[]) => mockGetReleaseManifest(...args),
}))

import { MarketingShell } from '../components/layout/MarketingShell'
import { AppShell } from '../components/layout/AppShell'
import { ProtectedRoute } from '../components/routes/ProtectedRoute'

function LocationEcho() {
  const location = useLocation()
  return <div data-testid="location">{location.pathname}{location.search}{location.hash}</div>
}

function renderProtectedRoute(initialEntry: string) {
  return render(
    <MemoryRouter initialEntries={[initialEntry]} future={ROUTER_FUTURE_FLAGS}>
      <Routes>
        <Route element={<ProtectedRoute />}>
          <Route path="/app/account" element={<div>Account page</div>} />
        </Route>
        <Route path="/login" element={<LocationEcho />} />
      </Routes>
    </MemoryRouter>,
  )
}

function renderMarketingShell(isAuthenticated = false) {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
      },
    },
  })

  mockUsePlatformAuth.mockReturnValue({
    isAuthenticated,
    isLoading: false,
    logout: () => mockLogout(),
    toggleColorMode: () => mockToggleColorMode(),
    colorMode: 'dark',
    user: {
      name: 'Operator',
      plan: 'operator',
    },
  })

  return render(
    <QueryClientProvider client={queryClient}>
      <MemoryRouter future={ROUTER_FUTURE_FLAGS}>
        <MarketingShell eyebrow="Eyebrow" title="Title" lede="Lede">
          <div>Body</div>
        </MarketingShell>
      </MemoryRouter>
    </QueryClientProvider>,
  )
}

describe('website route and shell behavior', () => {
  beforeEach(() => {
    cleanup()
    mockUsePlatformAuth.mockReset()
    mockLogout.mockReset()
    mockToggleColorMode.mockReset()
    mockGetAuthHealth.mockReset()
    mockGetReleaseManifest.mockReset()
    mockUsePlatformAuth.mockReturnValue({
      isAuthenticated: false,
      isLoading: false,
      logout: () => mockLogout(),
      toggleColorMode: () => mockToggleColorMode(),
      colorMode: 'dark',
      user: {
        name: 'Operator',
        plan: 'operator',
      },
    })
    mockGetAuthHealth.mockResolvedValue({
      ok: true,
      service: 'hypertwist-auth-server',
      supertokens: {
        configured: true,
        reachable: true,
        ready: true,
        apiVersion: '5.4',
        error: null,
        oauth: {
          github: false,
          google: false,
        },
      },
      fallback: {
        enabled: true,
        active: false,
        reason: null,
      },
      billing: {
        statePath: '/var/lib/hypertwist/auth/hypertwist-billing-state.json',
        processedEventCount: 0,
        pricePlanMapConfigured: false,
        productPlanMapConfigured: false,
        webhookSecretConfigured: false,
      },
      runtime: {
        mode: 'mixed',
        public_origin_ready: true,
        cookie_secure: true,
        api_domain: 'https://hypertwist.app',
        website_domain: 'https://hypertwist.app',
        warnings: [],
        errors: [],
      },
    })
    mockGetReleaseManifest.mockResolvedValue({
      ok: true,
      manifest: {
        generated_at: '2026-06-22T12:00:00.000Z',
        support_email: 'hello@hypertwist.app',
        public_docs_url: 'https://docs.hypertwist.app',
        release_notes_url: 'https://notes.hypertwist.app',
        corresponding_source_url: 'https://hypertwist.app/open-source/source.zip',
        open_source_repo_url: 'https://github.com/hypertwist/hypertwist',
        viewer: {
          authenticated: false,
          canDownload: false,
          plan: null,
          role: null,
          accessStatus: null,
        },
        platforms: [],
      },
    })
  })

  it('shows the protected-route loader while auth state is still resolving', () => {
    mockUsePlatformAuth.mockReturnValue({
      isAuthenticated: false,
      isLoading: true,
    })

    const { container } = renderProtectedRoute('/app/account')

    expect(screen.getByText('Loading your account...')).toBeTruthy()
    expect(screen.getByText('Signed-in website access')).toBeTruthy()
    expect(screen.getByText(/Checking your saved session, download access, and desktop pairing/i)).toBeTruthy()
    expect(container.querySelector('.general-page-loader-shell--fullscreen')).not.toBeNull()
    expect(screen.getByAltText('HyperTwist')).toBeTruthy()
    expect(screen.getByRole('link', { name: 'Open sign-in' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Faccount')
    expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access')
  })

  it('redirects unauthenticated protected routes to login with the full encoded next target', async () => {
    renderProtectedRoute('/app/account?tab=billing#security')

    expect((await screen.findByTestId('location')).textContent).toBe('/login?next=%2Fapp%2Faccount%3Ftab%3Dbilling%23security')
  })

  it('renders the protected outlet when authentication is present', () => {
    mockUsePlatformAuth.mockReturnValue({
      isAuthenticated: true,
      isLoading: false,
    })

    renderProtectedRoute('/app/account')

    expect(screen.getByText('Account page')).toBeTruthy()
  })

  it('switches the marketing-shell auth action between login and dashboard', () => {
    const { rerender } = renderMarketingShell(false)

    expect(screen.getByRole('link', { name: 'Log in' }).getAttribute('href')).toBe('/login')
    expect(screen.getAllByRole('link', { name: 'Features' }).every((link) => link.getAttribute('href') === '/features')).toBe(true)

    const queryClient = new QueryClient({
      defaultOptions: {
        queries: {
          retry: false,
        },
      },
    })

    mockUsePlatformAuth.mockReturnValue({
      isAuthenticated: true,
      isLoading: false,
      logout: () => mockLogout(),
      toggleColorMode: () => mockToggleColorMode(),
      colorMode: 'dark',
      user: {
        name: 'Operator',
        plan: 'operator',
      },
    })

    rerender(
      <QueryClientProvider client={queryClient}>
        <MemoryRouter future={ROUTER_FUTURE_FLAGS}>
          <MarketingShell eyebrow="Eyebrow" title="Title" lede="Lede">
            <div>Body</div>
          </MarketingShell>
        </MemoryRouter>
      </QueryClientProvider>,
    )

    expect(screen.getByRole('link', { name: 'Open dashboard' }).getAttribute('href')).toBe('/app')
  })

  it('shows operator identity in the app shell and wires theme/logout actions', async () => {
    mockUsePlatformAuth.mockReturnValue({
      isAuthenticated: true,
      isLoading: false,
      logout: () => mockLogout(),
      toggleColorMode: () => mockToggleColorMode(),
      colorMode: 'dark',
      user: {
        name: 'Operator Prime',
        plan: 'studio',
      },
    })

    render(
      <MemoryRouter initialEntries={['/app']} future={ROUTER_FUTURE_FLAGS}>
        <Routes>
          <Route path="/app" element={<AppShell />}>
            <Route index element={<div>Overview content</div>} />
          </Route>
        </Routes>
      </MemoryRouter>,
    )

    expect(screen.getByText('Operator Prime')).toBeTruthy()
    expect(screen.getByText('studio plan')).toBeTruthy()
    expect(screen.getByText('Overview content')).toBeTruthy()
    expect(screen.getByText('Desktop-first operator lane')).toBeTruthy()
    expect(screen.getByRole('link', { name: 'Launch Status' }).getAttribute('href')).toBe('/app/launch-status')
    expect(screen.getByRole('link', { name: 'Protected launch status' }).getAttribute('href')).toBe('/app/launch-status')
    expect(screen.getByRole('link', { name: 'Public download guidance' }).getAttribute('href')).toBe('/download')
    expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices')
    expect(screen.getByRole('link', { name: 'Operator access support' }).getAttribute('href')).toBe('/support?topic=operator-access')

    await userEvent.click(screen.getByRole('button', { name: 'Switch to light mode' }))
    await userEvent.click(screen.getByRole('button', { name: 'Log out' }))

    expect(mockToggleColorMode).toHaveBeenCalledTimes(1)
    expect(mockLogout).toHaveBeenCalledTimes(1)
  })
})
