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

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
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 { formatRial } from '../lib/utils';
import NewSessionPage from './NewSessionPage';

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

const record = (profileOver: object = {}) => ({
  uuid: 'r1',
  user_name: 'ساغر صابری',
  profile: { full_name: 'ساغر صابری', basic_insurance_id: null, supplementary_insurance_id: null, ...profileOver },
});

function mockGets(over: Partial<Record<string, unknown>> = {}) {
  get.mockImplementation((url: string) => {
    if (url === '/api/v1/patient/r1') return Promise.resolve({ success: true, data: over.record ?? record() });
    if (url === '/api/v1/service-sections') {
      return Promise.resolve({ success: true, data: over.sections ?? [{ uuid: 'sec1', name: 'بخش زیبایی' }] });
    }
    if (url === '/api/v1/service-items/sec1') {
      return Promise.resolve({
        success: true,
        data: over.items ?? [
          { uuid: 'svc1', name: 'کاشت مو', price_rials: 2_400_000, active: true, insurance_covered: false, staff: null },
        ],
      });
    }
    if (url === '/api/v1/staff') {
      return Promise.resolve({ success: true, data: over.staff ?? [{ uuid: 'st1', full_name: 'علی رضایی', active: true }] });
    }
    if (url === '/api/v1/inventory-items') {
      return Promise.resolve({
        success: true,
        data: { items: over.inventory ?? [{ uuid: 'inv1', name: 'عینک', unit: 'عدد', price: 1_200_000, stock: 10, status: 'in_stock' }], stats: {} },
      });
    }
    if (url === '/api/v1/inventory-packages') {
      return Promise.resolve({ success: true, data: over.packages ?? [{ uuid: 'pkg1', title: 'پکیج شماره یک', total: 2_400_000, available: true }] });
    }
    if (url === '/api/v1/billing/tenant-insurances') {
      return Promise.resolve({ success: true, data: { data: over.contracts ?? [] } });
    }
    if (url === '/api/v1/insurance-pricing') {
      return Promise.resolve({ success: true, data: { free_visit_price_rials: 500_000 } });
    }
    if (url === '/api/v1/patient/r1/sessions') {
      return Promise.resolve({ success: true, data: over.sessions ?? [] });
    }
    if (url === '/api/v1/patient/r1/wallet') {
      return Promise.resolve({ success: true, data: { balance_rials: 300_000, recent_transactions: [] } });
    }
    return Promise.resolve({ success: true, data: [] });
  });
}

function renderPage() {
  return renderWithProviders(
    <Routes>
      <Route path="/admin/patients/:recordUuid/session/new" element={<NewSessionPage />} />
    </Routes>,
    { route: '/admin/patients/r1/session/new' },
  );
}

/** انتخاب گزینه از SearchableSelect (react-select) با inputId */
async function pickOption(inputId: string, option: string) {
  const input = document.getElementById(inputId) as HTMLInputElement;
  fireEvent.focus(input);
  fireEvent.keyDown(input, { key: 'ArrowDown' });
  fireEvent.click(await screen.findByText(option));
}

beforeEach(() => {
  get.mockReset();
  post.mockReset();
});

describe('NewSessionPage (ویزارد ثبت مراجعه — پورت tauri create-service)', () => {
  it('renders the 3-step stepper and step-1 fields (tauri Step1Details)', async () => {
    mockGets();
    renderPage();

    // استپر سه گام («ایجاد سرویس» هم برچسب گام است هم دکمه ثبت)
    expect((await screen.findAllByText('ایجاد سرویس')).length).toBeGreaterThanOrEqual(2);
    expect(screen.getByText('پرداخت')).toBeInTheDocument();
    expect(screen.getByText('جزییات')).toBeInTheDocument();
    // فیلدهای گام ۱
    expect(screen.getByText('تاریخ پذیرش')).toBeInTheDocument();
    expect(screen.getByText('ساعت پذیرش')).toBeInTheDocument();
    expect(screen.getByText('انتخاب بخش')).toBeInTheDocument();
    expect(screen.getByText('انتخاب سرویس')).toBeInTheDocument();
    expect(screen.getByText('پرسنل')).toBeInTheDocument();
    expect(screen.getByText('انتخاب کالای مصرفی')).toBeInTheDocument();
    expect(screen.getByText('انتخاب پکیج')).toBeInTheDocument();
    // پذیرش‌کننده + breadcrumb بیمار
    expect(screen.getByText(/پذیرش کننده:/)).toBeInTheDocument();
    expect((await screen.findAllByText('ساغر صابری')).length).toBeGreaterThan(0);
    // بدون سرویس بیمه‌دار و بدون بیمه‌ی پروفایل → بلوک بیمه پنهان
    expect(screen.queryByText('بیمه پایه')).not.toBeInTheDocument();
  });

  it('shows the insurance block when patient profile has insurance', async () => {
    mockGets({ record: record({ basic_insurance_id: 7 }) });
    renderPage();

    expect(await screen.findByText('بیمه پایه')).toBeInTheDocument();
    expect(screen.getByText('بیمه تکمیلی')).toBeInTheDocument();
  });

  it('creates the session with session_at, consumables, package and staff then moves to payment step', async () => {
    mockGets({
      sessions: [{
        uuid: 's-new', services: [], visit_price_rials: 500_000, final_price_rials: 1_700_000,
        patient_debt_rials: 1_700_000, discount_rials: 0, payments: [], is_paid: false,
      }],
    });
    post.mockResolvedValue({ success: true, data: { uuid: 's-new' } });
    renderPage();

    await screen.findByText('انتخاب بخش');

    // بخش → سرویس → افزودن
    await pickOption('section-select', 'بخش زیبایی');
    await waitFor(() => expect(get).toHaveBeenCalledWith('/api/v1/service-items/sec1'));
    await pickOption('service-select', 'کاشت مو');
    fireEvent.click(screen.getByLabelText('افزودن سرویس'));
    expect(screen.getByText('خدمات انتخاب شده')).toBeInTheDocument();

    // کالای مصرفی: عینک
    await pickOption('consumable-select', 'عینک');
    fireEvent.click(screen.getByLabelText('افزودن کالا'));
    expect(screen.getByText(`مجموع قیمت کالاها: ${formatRial(1_200_000)}`)).toBeInTheDocument();

    // ثبت
    fireEvent.click(screen.getByText('ایجاد سرویس', { selector: 'button' }));
    await waitFor(() => expect(post).toHaveBeenCalledTimes(1));

    const [url, body] = post.mock.calls[0] as [string, any];
    expect(url).toBe('/api/v1/patient/r1/session');
    expect(typeof body.session_at).toBe('number');
    expect(body.payment_method).toBe('pending');
    expect(body.services).toEqual([{ service_item_uuid: 'svc1', quantity: 1 }]);
    expect(body.consumables).toEqual([{ inventory_item_uuid: 'inv1', quantity: 1 }]);
    // بدون بیمه → درصدها صفر و id ارسال نمی‌شود
    expect(body.base_insurance_discount_percent).toBe(0);
    expect(body.insurance_base_id).toBeUndefined();

    // ورود به گام پرداخت با دیتای واقعی session ساخته‌شده
    expect(await screen.findByText('هزینه سرویس:')).toBeInTheDocument();
    expect(screen.getByText('موجودی کیف پول:')).toBeInTheDocument();
    expect(screen.getAllByText(formatRial(1_700_000)).length).toBeGreaterThan(0);
  });

  it('increments consumable quantity via the counter and reflects the total', async () => {
    mockGets();
    renderPage();

    await screen.findByText('انتخاب کالای مصرفی');
    await pickOption('consumable-select', 'عینک');
    fireEvent.click(screen.getByLabelText('افزودن کالا'));

    fireEvent.click(screen.getByLabelText('افزایش'));
    expect(screen.getByText(`مجموع قیمت کالاها: ${formatRial(2_400_000)}`)).toBeInTheDocument();

    // کاهش تا صفر → حذف
    fireEvent.click(screen.getByLabelText('کاهش'));
    fireEvent.click(screen.getByLabelText('کاهش'));
    expect(screen.getByText('کالایی انتخاب نشده است')).toBeInTheDocument();
  });

  it('renders empty option lists without crashing (بدون بخش/کالا/پکیج)', async () => {
    mockGets({ sections: [], inventory: [], packages: [], staff: [] });
    renderPage();

    expect(await screen.findByText('انتخاب بخش')).toBeInTheDocument();
    expect(screen.getByText('کالایی انتخاب نشده است')).toBeInTheDocument();
    // مجموع صفر
    expect(screen.getByText(`مجموع قیمت کالاها: ${formatRial(0)}`)).toBeInTheDocument();
  });
});
