// @vitest-environment happy-dom
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'

// Own the three backends the General tab reads: the `settings` global
// (site info / locale), the shared `/seo/config` (site URL + robots), and the
// computed `/seo/index-status` (the status card).
// Mutable per-test environment so individual tests can simulate production.
let statusEnvironment = 'preview'

const STATUS = {
  status: 'protected',
  severity: 'warning',
  label: 'Protected',
  description: 'Non-production environment is noindexed. Production remains unaffected.',
  checks: [
    { key: 'environment', label: 'Environment', value: 'Preview', status: 'pass' },
    { key: 'siteUrl', label: 'Site URL configured', value: 'Yes', status: 'pass' },
    { key: 'sitemap', label: 'Sitemap enabled', value: 'Yes', status: 'pass' },
  ],
  actions: [
    { label: 'Run SEO Audit', href: '/seo?tab=audit', action: 'run_seo_audit' },
    { label: 'View robots.txt', href: '/robots.txt' },
  ],
  lastAuditAt: null,
}

const cmsApi = vi.fn(async (endpoint: string, options?: { method?: string }) => {
  const method = options?.method ?? 'GET'
  if (endpoint === '/globals/settings' && method === 'GET') {
    return {
      data: {
        siteTitle: 'Actuate Media',
        tagline: 'A lightweight content management system',
        language: 'en-US',
        timezone: 'America/Los_Angeles',
        aiProvider: 'anthropic',
      },
      status: 200,
    }
  }
  if (endpoint === '/seo/config' && method === 'GET') {
    return {
      data: {
        static: { site: null },
        overrides: { site: {} },
        effective: {
          site: {
            siteUrl: 'https://actuatemedia.com',
            robots: { defaultNoIndex: false, defaultNoFollow: false, noIndexNonProduction: true },
          },
        },
      },
      status: 200,
    }
  }
  if (endpoint === '/seo/index-status' && method === 'GET') {
    return { data: { ...STATUS, environment: statusEnvironment }, status: 200 }
  }
  return { data: {}, status: 200 }
})

vi.mock('../../lib/api.js', () => ({ cmsApi: (e: string, o?: unknown) => cmsApi(e, o as any) }))

const { GeneralSettingsTab } = await import('../../views/settings/GeneralSettingsTab.js')

beforeEach(() => {
  cmsApi.mockClear()
  statusEnvironment = 'preview'
})

describe('GeneralSettingsTab', () => {
  it('renders the index status pill, loaded site info, and a clean (disabled) save bar', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)

    await screen.findByLabelText('Site Title')
    const statusCard = screen.getByRole('region', { name: 'Site Index Status' })
    expect(within(statusCard).getByText('Protected')).toBeTruthy()
    expect((screen.getByLabelText('Site Title') as HTMLInputElement).value).toBe('Actuate Media')
    expect((screen.getByLabelText('Site URL') as HTMLInputElement).value).toBe(
      'https://actuatemedia.com',
    )
    // Nothing dirty yet → Save disabled.
    expect(
      (screen.getByRole('button', { name: 'Save Changes' }) as HTMLButtonElement).disabled,
    ).toBe(true)
  })

  it('enables Save when a field changes and persists site info to the settings global', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)
    const title = (await screen.findByLabelText('Site Title')) as HTMLInputElement

    fireEvent.change(title, { target: { value: 'Actuate Media Co' } })
    const save = screen.getByRole('button', { name: 'Save Changes' }) as HTMLButtonElement
    expect(save.disabled).toBe(false)

    fireEvent.click(save)

    await waitFor(() =>
      expect(cmsApi).toHaveBeenCalledWith(
        '/globals/settings',
        expect.objectContaining({ method: 'PUT' }),
      ),
    )
  })

  it('blocks save and shows an error for an invalid Site URL', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)
    await screen.findByLabelText('Site Title')
    const url = screen.getByLabelText('Site URL') as HTMLInputElement

    fireEvent.change(url, { target: { value: 'not a url' } })

    expect((await screen.findAllByText(/valid absolute URL/i)).length).toBeGreaterThan(0)
    expect(
      (screen.getByRole('button', { name: 'Save Changes' }) as HTMLButtonElement).disabled,
    ).toBe(true)
  })

  it('confirms before turning OFF non-production noindex', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)
    await screen.findByLabelText('Site Title')

    // The non-production noindex toggle is ON; clicking it should request confirmation.
    fireEvent.click(screen.getByRole('switch', { name: 'Noindex Non-Production Environments' }))

    expect(
      await screen.findByText(/Preview and staging environments may become indexable/i),
    ).toBeTruthy()
  })

  it('shows an "Unsaved changes" hint when a toggle is flipped but not yet saved', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)
    await screen.findByLabelText('Site Title')

    expect(screen.queryByText('Unsaved changes')).toBeNull()
    fireEvent.click(screen.getByRole('switch', { name: 'Default No Follow' }))

    expect(await screen.findByText('Unsaved changes')).toBeTruthy()
    expect(
      (screen.getByRole('button', { name: 'Save Changes' }) as HTMLButtonElement).disabled,
    ).toBe(false)
  })

  it('explains that noindex-non-production cannot affect a production deployment', async () => {
    statusEnvironment = 'production'
    render(<GeneralSettingsTab role="ADMIN" />)
    await screen.findByLabelText('Site Title')

    expect(screen.getByText(/this setting does not change pages served here/i)).toBeTruthy()
  })

  it('hides the production note on non-production environments', async () => {
    render(<GeneralSettingsTab role="ADMIN" />)
    await screen.findByLabelText('Site Title')

    expect(screen.queryByText(/this setting does not change pages served here/i)).toBeNull()
  })

  it('is read-only for non-admins', async () => {
    render(<GeneralSettingsTab role="EDITOR" />)

    expect(await screen.findByText(/read-only access to settings/i)).toBeTruthy()
    expect((screen.getByLabelText('Site Title') as HTMLInputElement).disabled).toBe(true)
  })
})
