import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { DisputeDetailClient } from '../dispute-detail-client';

const showMock = vi.fn();
const adjudicateMock = vi.fn();
const submitEvidenceMock = vi.fn();
vi.mock('@/lib/api', () => ({
  api: {
    admin: {
      showDispute: (...a: unknown[]) => showMock(...a),
      adjudicate: (...a: unknown[]) => adjudicateMock(...a),
      submitEvidence: (...a: unknown[]) => submitEvidenceMock(...a),
    },
  },
}));

function wrap(node: React.ReactNode) {
  const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  return <QueryClientProvider client={qc}>{node}</QueryClientProvider>;
}

const detail = {
  id: 'd1',
  purchase_id: 'p1',
  stripe_dispute_id: 'dp_x',
  status: 'needs_response',
  reason: 'product_not_received',
  amount_cents: 12_800,
  evidence_due_by: '2026-05-10T00:00:00Z',
  buyer_first_name: 'Jane',
  buyer_last_name: 'Doe',
  outcome: null,
  decided_at: null,
  created_at: '2026-05-04T00:00:00Z',
  decision_justification: null,
  purchase: {
    id: 'p1',
    stripe_payment_intent_id: 'pi_1',
    shipping_address: { first_name: 'Jane', last_name: 'Doe' },
    subtotal: 10000,
    shipping_total: 2800,
  },
  orders: [
    {
      id: 'o1',
      store: { id: 's1', name: 'Store A' },
      status: 'shipped',
      subtotal: 5000,
      shipping_cost: 1400,
      stripe_transfer_id: 'tr_1',
      transferred_at: '2026-05-01T00:00:00Z',
      transfer_reversed_at: null,
      tracking_number: '1Z',
      tracking_url: null,
      shipped_at: '2026-05-01T00:00:00Z',
    },
    {
      id: 'o2',
      store: { id: 's2', name: 'Store B' },
      status: 'shipped',
      subtotal: 5000,
      shipping_cost: 1400,
      stripe_transfer_id: 'tr_2',
      transferred_at: '2026-05-01T00:00:00Z',
      transfer_reversed_at: null,
      tracking_number: '1Z',
      tracking_url: null,
      shipped_at: '2026-05-01T00:00:00Z',
    },
  ],
};

describe('DisputeDetailClient', () => {
  beforeEach(() => {
    showMock.mockReset();
    adjudicateMock.mockReset();
    submitEvidenceMock.mockReset();
  });

  it('renders evidence panel and per-order rows', async () => {
    showMock.mockResolvedValue({ data: detail });
    render(wrap(<DisputeDetailClient purchaseId="p1" />));
    await waitFor(() => expect(screen.getByText('Store A')).toBeInTheDocument());
    expect(screen.getByText('Store B')).toBeInTheDocument();
    expect(screen.getByText(/product_not_received/)).toBeInTheDocument();
  });

  it('Accept outcome shows per-order toggles, opens confirm dialog, submits', async () => {
    showMock.mockResolvedValue({ data: detail });
    adjudicateMock.mockResolvedValue({ data: detail });
    render(wrap(<DisputeDetailClient purchaseId="p1" />));
    await waitFor(() => expect(screen.getByText('Store A')).toBeInTheDocument());

    fireEvent.click(screen.getByRole('radio', { name: /Accept dispute/ }));
    const reverseChecks = screen.getAllByLabelText(/Reverse transfer/);
    expect(reverseChecks).toHaveLength(2);
    reverseChecks.forEach((c) => fireEvent.click(c));

    fireEvent.click(screen.getByRole('button', { name: /Submit decision/ }));
    fireEvent.change(screen.getByLabelText('Justification'), {
      target: { value: 'Buyer evidence is conclusive — refund both stores.' },
    });
    fireEvent.click(screen.getByRole('button', { name: 'Confirm' }));
    await waitFor(() => expect(adjudicateMock).toHaveBeenCalled());
    const [, body] = adjudicateMock.mock.calls[0];
    expect(body.outcome).toBe('accepted');
    expect(body.per_order_actions).toHaveLength(2);
    expect(
      body.per_order_actions.every((a: { reverse_transfer: boolean }) => a.reverse_transfer),
    ).toBe(true);
  });

  it('Submit-evidence outcome calls submitEvidence not adjudicate', async () => {
    showMock.mockResolvedValue({ data: detail });
    submitEvidenceMock.mockResolvedValue({ data: detail });
    render(wrap(<DisputeDetailClient purchaseId="p1" />));
    await waitFor(() => expect(screen.getByText('Store A')).toBeInTheDocument());

    fireEvent.click(screen.getByRole('radio', { name: /Submit evidence/ }));
    fireEvent.click(screen.getByRole('button', { name: /Submit decision/ }));
    fireEvent.change(screen.getByLabelText('Justification'), {
      target: { value: 'Tracking confirms delivery — contesting the dispute.' },
    });
    fireEvent.click(screen.getByRole('button', { name: 'Confirm' }));
    await waitFor(() => expect(submitEvidenceMock).toHaveBeenCalled());
    expect(adjudicateMock).not.toHaveBeenCalled();
  });
});
