import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { EscalateReturnButton } from '../escalate-return-button';
import type { OrderReturn, ReturnEscalation, ReturnState } from '@alqove/api-client';

const escalateMock = vi.fn();
vi.mock('@/lib/api', () => ({
  api: {
    returns: {
      escalate: (...a: unknown[]) => escalateMock(...a),
    },
  },
}));

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

const baseReturn: OrderReturn = {
  id: 'r1',
  order_id: 'o1',
  initiated_by: 'buyer',
  state: 'approved',
  reason: 'damaged',
  reason_text: null,
  return_shipping_payer: 'seller',
  restocking_fee_cents: 0,
  refund_amount_cents: null,
  refund_original_shipping: false,
  refund_amount_override_cents: null,
  stripe_refund_id: null,
  tracking_number: null,
  carrier: null,
  tracker_id: null,
  tracking_url: null,
  shipping_label_url: null,
  easypost_label_error: null,
  items: [],
  approved_at: '2026-05-07T10:00:00Z',
  rejected_at: null,
  label_issued_at: null,
  in_transit_at: null,
  received_at: null,
  refunded_at: null,
  closed_at: null,
  cancelled_at: null,
  escalation: null,
  created_at: '2026-05-07T10:00:00Z',
  updated_at: '2026-05-07T10:00:00Z',
};

const baseEscalation: ReturnEscalation = {
  id: 'e1',
  return_id: 'r1',
  escalated_by_user_id: 'u1',
  reason: 'seller has not shipped a label',
  state: 'open',
  resolved_by_admin_id: null,
  resolution: null,
  action: null,
  resolved_at: null,
  created_at: '2026-05-07T11:00:00Z',
  updated_at: '2026-05-07T11:00:00Z',
};

describe('EscalateReturnButton', () => {
  beforeEach(() => {
    escalateMock.mockReset();
  });

  it('shows escalate button in approved/awaiting_shipment/in_transit/received', () => {
    const states: ReturnState[] = ['approved', 'awaiting_shipment', 'in_transit', 'received'];
    for (const state of states) {
      const { unmount } = render(
        wrap(<EscalateReturnButton return={{ ...baseReturn, state }} />),
      );
      expect(
        screen.getByRole('button', { name: /Need help with this return/i }),
      ).toBeInTheDocument();
      unmount();
    }
  });

  it('hides button when state is requested', () => {
    render(wrap(<EscalateReturnButton return={{ ...baseReturn, state: 'requested' }} />));
    expect(
      screen.queryByRole('button', { name: /Need help with this return/i }),
    ).toBeNull();
  });

  it('hides button when state is refunded or closed', () => {
    for (const state of ['refunded', 'closed'] as const) {
      const { unmount } = render(
        wrap(<EscalateReturnButton return={{ ...baseReturn, state }} />),
      );
      expect(
        screen.queryByRole('button', { name: /Need help with this return/i }),
      ).toBeNull();
      unmount();
    }
  });

  it('hides button and shows banner when an open escalation exists', () => {
    render(
      wrap(
        <EscalateReturnButton return={{ ...baseReturn, escalation: baseEscalation }} />,
      ),
    );
    expect(
      screen.queryByRole('button', { name: /Need help with this return/i }),
    ).toBeNull();
    expect(screen.getByText(/Escalation submitted/i)).toBeInTheDocument();
  });

  it('shows resolved banner when escalation is resolved', () => {
    render(
      wrap(
        <EscalateReturnButton
          return={{
            ...baseReturn,
            escalation: {
              ...baseEscalation,
              state: 'resolved',
              action: 'force_refund',
              resolution: 'Buyer was refunded in full.',
              resolved_at: '2026-05-08T10:00:00Z',
              resolved_by_admin_id: 'admin1',
            },
          }}
        />,
      ),
    );
    expect(screen.getByText(/Resolved by admin/i)).toBeInTheDocument();
    expect(screen.getByText(/Buyer was refunded in full/i)).toBeInTheDocument();
  });

  it('submit calls useEscalateReturn with { reason }', async () => {
    escalateMock.mockResolvedValueOnce({
      data: { ...baseEscalation, reason: 'a'.repeat(20) },
    });
    render(wrap(<EscalateReturnButton return={baseReturn} />));
    fireEvent.click(screen.getByRole('button', { name: /Need help/i }));
    fireEvent.change(screen.getByRole('textbox'), {
      target: { value: 'seller has not shipped' },
    });
    fireEvent.click(screen.getByRole('button', { name: /^Submit$/i }));
    await waitFor(() =>
      expect(escalateMock).toHaveBeenCalledWith('r1', 'seller has not shipped'),
    );
  });

  it('submit disabled when reason < 10 chars', () => {
    render(wrap(<EscalateReturnButton return={baseReturn} />));
    fireEvent.click(screen.getByRole('button', { name: /Need help/i }));
    fireEvent.change(screen.getByRole('textbox'), { target: { value: 'short' } });
    const submit = screen.getByRole('button', { name: /^Submit$/i }) as HTMLButtonElement;
    expect(submit.disabled).toBe(true);
  });

  it('successful submit closes dialog', async () => {
    escalateMock.mockResolvedValueOnce({ data: baseEscalation });
    render(wrap(<EscalateReturnButton return={baseReturn} />));
    fireEvent.click(screen.getByRole('button', { name: /Need help/i }));
    fireEvent.change(screen.getByRole('textbox'), {
      target: { value: 'seller has not shipped' },
    });
    fireEvent.click(screen.getByRole('button', { name: /^Submit$/i }));
    await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());
  });
});
