/**
 * @jest-environment jsdom
 *
 * Tests for the Site Performance section of DealerDetailModal (PR #902).
 *
 * The modal loads three endpoints in a Promise.all on open:
 *   1. /detail   2. /activity   3. /stats  (the performance endpoint)
 * The Site Performance section only renders when the stats fetch is ok AND
 * the payload has a truthy `traffic`. A non-ok stats response must leave the
 * section hidden and emit a console.warn (so it's distinguishable from a
 * dealer with simply no traffic).
 *
 * Mock setup mirrors DealerDetailModal.gsc.test.tsx exactly.
 */

import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { DealerDetailModal } from '../DealerDetailModal';

// ---- Module mocks (identical to the GSC sibling test) --------------------

jest.mock('@/lib/status-transitions', () => ({
  STATUS_CHANGE_REASONS: [],
}));

jest.mock('@/lib/dealer-site-url', () => ({
  getDealerSiteUrl: jest.fn(() => 'https://bob.myamsoil.com'),
}));

jest.mock('@/lib/seo-utils', () => ({
  getCanonicalUrl: jest.fn(() => 'https://bob.myamsoil.com'),
}));

jest.mock('@/components/ui/Modal', () => ({
  Modal: ({ children, isOpen }: { children: React.ReactNode; isOpen: boolean }) =>
    isOpen ? <div data-testid="modal">{children}</div> : null,
}));

// ---- Fixtures --------------------------------------------------------------

const DEALER = {
  id: 'dealer-1',
  businessName: "Bob's Oil",
  subdomain: 'bob',
  domain: 'com',
  domainPrefix: 'myamsoil',
  customDomain: null,
  customDomainStatus: 'none',
  subscriptionTier: 'growth',
  status: 'active',
  dealerNumber: null,
  phone: '555-5555',
  address: '1 Main',
  city: 'Topeka',
  state: 'KS',
  zip: '66601',
  country: 'US',
  contactName: 'Bob',
  contactEmail: 'bob@example.com',
  stripeCustomerId: 'cus_x',
  stripeSubscriptionId: null,
  hasLeadForm: false,
  hasGrandfatheredCustomDomain: false,
  createdAt: '2024-01-01T00:00:00Z',
  updatedAt: '2024-01-01T00:00:00Z',
  lastPublishedAt: null,
  gscVerificationToken: null,
  gscPropertyRegisteredAt: null,
  gscLastInspectedAt: null,
  gscLastIndexStatus: null,
  gscLastSubmittedAt: null,
  gscPreflightHealthyAt: null,
  gscPreflightError: null,
  user: {
    id: 'u1',
    email: 'bob@example.com',
    name: 'Bob',
    role: 'user',
    createdAt: '2024-01-01T00:00:00Z',
  },
  stats: { pages: 0, leads: 0, pageViews: 0, notes: 0, recentActivity: 0 },
};

const PERFORMANCE = {
  traffic: { current: 4321, previous: 4000, changePercent: 8.0 },
  inquiries: { current: 12, previous: 15, changePercent: -20.0 },
  clicks: { current: 678 },
};

function okResponse(body: unknown): Response {
  return { ok: true, status: 200, json: async () => body } as Response;
}

function notOkResponse(status: number, body: unknown = {}): Response {
  return { ok: false, status, json: async () => body } as Response;
}

/**
 * Wires the three Promise.all fetches in order: detail, activity, stats.
 * The third (stats) response is the variable under test.
 */
function wireFetches(statsRes: Response) {
  global.fetch = jest
    .fn()
    .mockResolvedValueOnce(okResponse({ dealer: DEALER, gscJobs: [], activity: [] }))
    .mockResolvedValueOnce(okResponse({ activity: [] }))
    .mockResolvedValueOnce(statsRes) as unknown as typeof fetch;
}

describe('DealerDetailModal — Site Performance section (#902)', () => {
  const realFetch = global.fetch;
  let warnSpy: jest.SpyInstance;

  beforeEach(() => {
    warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
  });

  afterEach(() => {
    global.fetch = realFetch;
    warnSpy.mockRestore();
    jest.clearAllMocks();
  });

  it('renders the Site Performance section when the stats fetch returns traffic data', async () => {
    wireFetches(okResponse(PERFORMANCE));

    render(<DealerDetailModal isOpen dealerId="dealer-1" onClose={jest.fn()} />);

    await waitFor(() => {
      expect(screen.getByText('Site Performance — Last 30 Days')).toBeInTheDocument();
    });
    // Traffic, inquiries, and link-click values are rendered (toLocaleString).
    expect(screen.getByText('4,321')).toBeInTheDocument();
    expect(screen.getByText('678')).toBeInTheDocument();
    expect(warnSpy).not.toHaveBeenCalled();
  });

  it('hides the section and warns when the stats fetch is non-ok', async () => {
    wireFetches(notOkResponse(500));

    render(<DealerDetailModal isOpen dealerId="dealer-1" onClose={jest.fn()} />);

    // Wait for the modal to finish loading (the dealer name is shown once loaded).
    await waitFor(() => {
      expect(screen.getByRole('button', { name: /reindex now/i })).toBeInTheDocument();
    });

    // Section must NOT be rendered.
    expect(screen.queryByText('Site Performance — Last 30 Days')).not.toBeInTheDocument();

    // A console.warn must fire mentioning the HTTP status and dealer id.
    await waitFor(() => {
      expect(warnSpy).toHaveBeenCalledWith(
        expect.stringContaining('Dealer performance stats unavailable (HTTP 500) for dealer-1')
      );
    });
  });

  it('hides the section (no warn) when stats is ok but has no traffic', async () => {
    wireFetches(okResponse({ inquiries: PERFORMANCE.inquiries, clicks: PERFORMANCE.clicks }));

    render(<DealerDetailModal isOpen dealerId="dealer-1" onClose={jest.fn()} />);

    await waitFor(() => {
      expect(screen.getByRole('button', { name: /reindex now/i })).toBeInTheDocument();
    });

    // ok response → no warn, but `performance.traffic` is undefined → section hidden.
    expect(screen.queryByText('Site Performance — Last 30 Days')).not.toBeInTheDocument();
    expect(warnSpy).not.toHaveBeenCalled();
  });
});
