import React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';

// BUG-03b regression: /approvals treats the response of /api/session/effective
// (which unifies NextAuth + local-session auth) as the source of truth for
// admin detection. These tests pin that contract and the settled-before-banner
// hydration behavior.

vi.mock('@/components/PageLayout', () => ({
  default: ({ title, children, actions }) => (
    <div>
      <h1>{title}</h1>
      <div>{actions}</div>
      <div>{children}</div>
    </div>
  ),
}));

vi.mock('@/components/ui/Card', () => ({
  Card: ({ children }) => <div>{children}</div>,
  CardContent: ({ children }) => <div>{children}</div>,
}));

vi.mock('@/components/ui/Badge', () => ({
  Badge: ({ children }) => <span>{children}</span>,
}));

vi.mock('@/components/ui/EmptyState', () => ({
  EmptyState: ({ title, description }) => (
    <div><div>{title}</div><div>{description}</div></div>
  ),
}));

vi.mock('@/lib/isDemoMode', () => ({
  isDemoMode: () => false,
}));

const READ_ONLY_TEXT = /Only administrators can approve or deny actions/i;

function makeFetch({ effective }) {
  return vi.fn(async (url) => {
    const u = String(url);
    if (u.startsWith('/api/actions')) {
      return { ok: true, json: async () => ({ actions: [] }) };
    }
    if (u === '/api/session/effective') {
      if (effective === 'ERROR') {
        return { ok: false, status: 500, json: async () => ({}) };
      }
      return {
        ok: true,
        json: async () => ({
          authenticated: !!effective,
          authType: effective?.authType || null,
          role: effective?.role ?? null,
          isAdmin: effective?.role === 'admin',
        }),
      };
    }
    return { ok: true, json: async () => ({}) };
  });
}

describe('ApprovalsPage — session resolution', () => {
  beforeEach(() => {
    // Each test sets its own fetch; start clean.
    global.fetch = undefined;
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('does not flash the read-only banner before session is settled', async () => {
    // Keep fetch pending so neither fetchPending nor /api/session/effective
    // resolves — sessionSettled must remain false and the banner must stay
    // hidden during the hydration window.
    global.fetch = vi.fn(() => new Promise(() => {}));

    const { default: ApprovalsPage } = await import('@/approvals/page.jsx');
    render(<ApprovalsPage />);

    expect(screen.queryByText(READ_ONLY_TEXT)).toBeNull();
  });

  it('hides the read-only banner for a NextAuth admin', async () => {
    global.fetch = makeFetch({ effective: { role: 'admin', authType: 'nextauth' } });

    const { default: ApprovalsPage } = await import('@/approvals/page.jsx');
    render(<ApprovalsPage />);

    // Wait for the empty state to confirm the page settled.
    await waitFor(() => expect(screen.getByText('All clear')).toBeTruthy());
    expect(screen.queryByText(READ_ONLY_TEXT)).toBeNull();
  });

  it('hides the read-only banner for a local-password admin (BUG-03b)', async () => {
    global.fetch = makeFetch({ effective: { role: 'admin', authType: 'local' } });

    const { default: ApprovalsPage } = await import('@/approvals/page.jsx');
    render(<ApprovalsPage />);

    await waitFor(() => expect(screen.getByText('All clear')).toBeTruthy());
    expect(screen.queryByText(READ_ONLY_TEXT)).toBeNull();
  });

  it('shows the read-only banner for a non-admin member', async () => {
    global.fetch = makeFetch({ effective: { role: 'member', authType: 'nextauth' } });

    const { default: ApprovalsPage } = await import('@/approvals/page.jsx');
    render(<ApprovalsPage />);

    await waitFor(() => expect(screen.getByText(READ_ONLY_TEXT)).toBeTruthy());
  });

  it('shows the read-only banner when /api/session/effective fails', async () => {
    global.fetch = makeFetch({ effective: 'ERROR' });

    const { default: ApprovalsPage } = await import('@/approvals/page.jsx');
    render(<ApprovalsPage />);

    await waitFor(() => expect(screen.getByText(READ_ONLY_TEXT)).toBeTruthy());
  });
});
