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 AppointmentActionsMenu from './AppointmentActions';
import type { Appointment } from '../types';

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

const navigate = vi.fn();
vi.mock('react-router-dom', async () => ({
  ...(await vi.importActual<typeof import('react-router-dom')>('react-router-dom')),
  useNavigate: () => navigate,
}));

const appt: Appointment = {
  uuid: 'ap1', patient_name: 'مریم خلیلی', patient_mobile: '09136549874',
  doctor_uuid: 'd1', doctor_name: 'دکتر احمدی',
  slot_start: 1735639200, slot_end: 1735641900, // 45 min
  appointment_date: '2024-12-31', appointment_time: '09:00', end_time: '09:45',
  status: 'confirmed', version: 3, created_at: '',
  service_section: { uuid: 's1', name: 'زیبایی' },
  service_item: { uuid: 'i1', name: 'لیزر توتال' },
  staff: { uuid: 'st1', full_name: 'دکتر حمیدی' },
};

beforeEach(() => {
  get.mockReset(); patch.mockReset();
  get.mockImplementation((url: string) => {
    if (url.startsWith('/api/v1/patients?search=')) return Promise.resolve({ success: true, data: [{ uuid: 'rec1' }] });
    if (url === '/api/v1/patient/rec1/wallet') return Promise.resolve({ success: true, data: { balance_rials: 500000, recent_transactions: [] } });
    return Promise.resolve({ success: true, data: [] });
  });
  patch.mockResolvedValue({ success: true, data: {} });
  post.mockReset();
  navigate.mockReset();
});

function openMenu() {
  renderWithProviders(<AppointmentActionsMenu appointment={appt} queryKey={['appts']} />);
  fireEvent.click(screen.getByRole('button', { name: 'عملیات' }));
}

describe('AppointmentActionsMenu (عملیات نوبت)', () => {
  it('lists all six actions from the Figma menu', () => {
    openMenu();
    for (const label of ['ویرایش', 'ثبت سرویس', 'مشاهده', 'جا به جایی نوبت', 'انتقال به لیست رزرو', 'جایگزینی نوبت']) {
      expect(screen.getByText(label)).toBeInTheDocument();
    }
  });

  it('«ثبت سرویس» پروندهٔ موجود بیمار را باز می‌کند', async () => {
    openMenu();
    fireEvent.click(screen.getByText('ثبت سرویس'));

    await waitFor(() => expect(navigate).toHaveBeenCalledWith('/admin/patients/rec1/session/new'));
    // مسیر جستجو باید همان endpoint واقعی باشد، وگرنه ۴۰۴ می‌گیرد و «خطا در یافتن پرونده» می‌دهد.
    expect(get).toHaveBeenCalledWith(expect.stringContaining('/api/v1/patients?search='));
    expect(post).not.toHaveBeenCalled();
  });

  it('«ثبت سرویس» برای بیمارِ بدون پرونده، اول پرونده می‌سازد', async () => {
    get.mockImplementation((url: string) => {
      if (url.startsWith('/api/v1/patients?search=')) return Promise.resolve({ success: true, data: [] });
      return Promise.resolve({ success: true, data: [] });
    });
    post.mockResolvedValue({ success: true, data: { uuid: 'rec-new' } });

    openMenu();
    fireEvent.click(screen.getByText('ثبت سرویس'));

    await waitFor(() => expect(post).toHaveBeenCalledWith('/api/v1/patient', expect.objectContaining({
      mobile: '09136549874',
      name: 'مریم خلیلی',
    })));
    expect(navigate).toHaveBeenCalledWith('/admin/patients/rec-new/session/new');
  });

  it('info modal shows appointment details and patient wallet balance', async () => {
    openMenu();
    fireEvent.click(screen.getByText('مشاهده'));
    expect(await screen.findByText('ساعت شروع:')).toBeInTheDocument();
    expect(screen.getByText('۴۵ دقیقه')).toBeInTheDocument();
    expect(screen.getByText('لیزر توتال')).toBeInTheDocument();
    expect(screen.getByText('دکتر حمیدی')).toBeInTheDocument();
    // wallet resolved through record search → balance shown (rial → toman)
    expect(await screen.findByText(/تومان/)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: 'مشاهده پرونده' })).toBeInTheDocument();
  });

  it('move modal patches new slot times', async () => {
    openMenu();
    fireEvent.click(screen.getByText('جا به جایی نوبت'));
    expect(await screen.findByText('اعمال تغییرات')).toBeInTheDocument();
    fireEvent.change(screen.getByLabelText('ساعت شروع'), { target: { value: '15:00' } });
    fireEvent.change(screen.getByLabelText('ساعت پایان'), { target: { value: '16:00' } });
    fireEvent.click(screen.getByText('اعمال تغییرات'));
    await waitFor(() => expect(patch).toHaveBeenCalledWith('/api/v1/appointment/ap1', expect.objectContaining({
      slot_start: Math.floor(new Date('2024-12-31T15:00').getTime() / 1000),
      slot_end: Math.floor(new Date('2024-12-31T16:00').getTime() / 1000),
      version: 3,
    })));
  });

  it('transfer modal flips is_reserve with a day-level slot', async () => {
    openMenu();
    fireEvent.click(screen.getByText('انتقال به لیست رزرو'));
    expect(await screen.findByText(/به لیست نوبت های رزرو شده منتقل می شود/)).toBeInTheDocument();
    fireEvent.click(screen.getByText('انتقال و حذف از لیست'));
    const day = Math.floor(new Date('2024-12-31T00:00').getTime() / 1000);
    await waitFor(() => expect(patch).toHaveBeenCalledWith('/api/v1/appointment/ap1', expect.objectContaining({
      is_reserve: true, slot_start: day, slot_end: day, version: 3,
    })));
  });

  it('replace modal swaps the patient and keeps the slot locked', async () => {
    openMenu();
    fireEvent.click(screen.getByText('جایگزینی نوبت'));
    expect(await screen.findByPlaceholderText('نام و نام خانوادگی')).toBeInTheDocument();
    // the original slot is shown read-only
    expect(screen.getByDisplayValue('2024-12-31')).toBeDisabled();
    expect(screen.getByDisplayValue('09:00')).toBeDisabled();
    // prefilled from the appointment's current specs (react-select single value)
    expect(screen.getByText('قطعی شده')).toBeInTheDocument();

    fireEvent.change(screen.getByPlaceholderText('نام و نام خانوادگی'), { target: { value: 'ساغر صابری' } });
    fireEvent.change(screen.getByPlaceholderText('شماره تماس'), { target: { value: '09356619438' } });
    fireEvent.click(screen.getByText('ثبت نوبت'));
    await waitFor(() => expect(patch).toHaveBeenCalledWith('/api/v1/appointment/ap1', expect.objectContaining({
      patient_name: 'ساغر صابری', patient_mobile: '09356619438',
      service_section_uuid: 's1', service_item_uuid: 'i1', staff_uuid: 'st1',
      version: 3,
    })));
  });

  it('replace modal picks an existing patient from the record search', async () => {
    get.mockImplementation((url: string) => {
      if (url.startsWith('/api/v1/patients?search=')) return Promise.resolve({ success: true, data: [
        { uuid: 'rec9', user_name: 'پریسا همتی', user_mobile: '09120009999' },
      ] });
      return Promise.resolve({ success: true, data: [] });
    });
    openMenu();
    fireEvent.click(screen.getByText('جایگزینی نوبت'));
    fireEvent.change(await screen.findByPlaceholderText('جستجوی نام، شماره تماس، شماره پرونده...'), { target: { value: 'پریسا' } });
    fireEvent.click(await screen.findByText('پریسا همتی'));
    fireEvent.click(screen.getByText('ثبت نوبت'));
    await waitFor(() => expect(patch).toHaveBeenCalledWith('/api/v1/appointment/ap1', expect.objectContaining({
      patient_name: 'پریسا همتی', patient_mobile: '09120009999',
    })));
  });
});
