import { describe, it, expect, beforeEach, vi } from 'vitest';
import { screen, fireEvent, waitFor } from '@testing-library/react';
import { renderWithProviders } from '../test/utils';

vi.mock('../lib/api', () => ({
  api: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn() },
  ApiError: class extends Error {},
}));

import { api } from '../lib/api';
import PatientRecordFormPage from './PatientRecordFormPage';

const get = api.get as ReturnType<typeof vi.fn>;
const post = api.post as ReturnType<typeof vi.fn>;

/** الگوی شمارهٔ پرونده؛ `enabled=false` یعنی رفتار قدیمیِ ورود دستی. */
function mockPattern(settings: Record<string, unknown>) {
  get.mockImplementation((url: string) =>
    url.includes('patient-record-number-settings')
      ? Promise.resolve({ success: true, data: { pattern: '{YY}-{SEQ:4}', reset_policy: 'none', counter: 0, next_preview: '05-0001', ...settings } })
      : Promise.resolve({ success: true, data: [] }),
  );
}

/**
 * پرکردن فیلدهای الزامیِ دیگر تا فقط شمارهٔ پرونده متغیر بماند.
 *
 * اول منتظر رسیدن تنظیمات می‌ماند: رندرِ بعد از پاسخ، منوی باز react-select را
 * می‌بندد و انتخاب جنسیت را می‌خورد.
 */
async function fillRequiredFields() {
  await waitFor(() => expect(get).toHaveBeenCalledWith(expect.stringContaining('patient-record-number-settings')));
  await waitFor(() => expect(screen.getByRole('button', { name: /ثبت|ذخیره/ })).toBeEnabled());

  fireEvent.change(await screen.findByPlaceholderText('نام و نام خانوادگی را وارد نمایید'), { target: { value: 'علی محمدی' } });
  fireEvent.change(screen.getByPlaceholderText('کد ملی را وارد نمایید'), { target: { value: '0012345675' } });
  fireEvent.change(screen.getByPlaceholderText('شماره تماس را وارد نمایید'), { target: { value: '09121234567' } });
  const gender = document.getElementById('patient-gender-select') as HTMLInputElement;
  fireEvent.focus(gender);
  fireEvent.keyDown(gender, { key: 'ArrowDown' });
  fireEvent.click(await screen.findByText('مرد'));
}

beforeEach(() => {
  get.mockReset();
  post.mockReset();
  post.mockResolvedValue({ success: true, data: { uuid: 'rec-new' } });
  (api.patch as ReturnType<typeof vi.fn>).mockResolvedValue({ success: true, data: {} });
});

describe('PatientRecordFormPage — شمارهٔ پرونده', () => {
  /** ⚠️ مرزی: بدون الگو، فیلد الزامی می‌ماند (رفتار امروز). */
  it('بدون الگو شماره پرونده الزامی است', async () => {
    mockPattern({ enabled: false, can_edit: true });
    renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });

    await fillRequiredFields();
    fireEvent.click(screen.getByText('ثبت اطلاعات') ?? screen.getByRole('button', { name: /ثبت|ذخیره/ }));

    expect(await screen.findByText('شماره پرونده الزامی است')).toBeInTheDocument();
    expect(post).not.toHaveBeenCalled();
  });

  /** ✅ موفق: با الگوی فعال و بدون اجازهٔ دستی، فیلد read-only است و ارسال نمی‌شود. */
  it('با الگوی فعال و بدون can_edit، شماره فرستاده نمی‌شود', async () => {
    mockPattern({ enabled: true, can_edit: false });
    renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });

    expect(await screen.findByText('شماره از الگوی مجموعه ساخته می‌شود')).toBeInTheDocument();

    await fillRequiredFields();
    fireEvent.click(screen.getByRole('button', { name: /ثبت|ذخیره/ }));

    await waitFor(() => expect(post).toHaveBeenCalled());
    expect(post.mock.calls[0][1]).not.toHaveProperty('record_number');
  });

  /** ✅ موفق: صاحب مجموعه می‌تواند خالی بگذارد تا سرور بسازد. */
  it('صاحب مجموعه می‌تواند شماره را خالی بگذارد', async () => {
    mockPattern({ enabled: true, can_edit: true });
    renderWithProviders(<PatientRecordFormPage />, { route: '/admin/patients/new' });

    expect(await screen.findByText(/خالی بماند تا از الگو ساخته شود/)).toBeInTheDocument();

    await fillRequiredFields();
    fireEvent.click(screen.getByRole('button', { name: /ثبت|ذخیره/ }));

    await waitFor(() => expect(post).toHaveBeenCalled());
    expect(post.mock.calls[0][1].record_number).toBe('');
  });
});
