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 {},
}));

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

vi.mock('../hooks/usePermissions', () => ({
  usePermissions: () => ({ can: () => true }),
}));

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

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

const branch = {
  id: '1', uuid: 'b1', type: 'clinic', clinic_id: 3, clinic_name: 'کلینیک',
  name: 'شعبهٔ مرکزی', map: { latitude: null, longitude: null }, address: null,
  telephone: null, active: true, timezone: 'Asia/Tehran', city: null, province: null,
};

const laserType = { uuid: 't1', code: 'laser', name: 'دستگاه لیزر', is_system: false, active: true, resources_count: 1, created_at: 0, updated_at: 0 };
const skill = { uuid: 's1', name: 'آلکساندرایت', active: true, resources_count: 1, created_at: 0, updated_at: 0 };

const resource = {
  uuid: 'r1', name: 'لیزر ۱', address_uuid: 'b1', address_name: 'شعبهٔ مرکزی',
  type_uuid: 't1', type_code: 'laser', type_name: 'دستگاه لیزر',
  capacity: 3, setup_minutes: 5, cleanup_minutes: 10, attributes: {},
  subject_kind: null, subject_uuid: null,
  skills: [{ skill_uuid: 's1', skill_name: 'آلکساندرایت', level: 4 }],
  active: true, created_at: 0, updated_at: 0,
};

function mockApi() {
  get.mockImplementation((path: string) => {
    if (path.startsWith('/api/v1/addresses')) return Promise.resolve({ success: true, data: [branch] });
    if (path.startsWith('/api/v1/resource-types')) return Promise.resolve({ success: true, data: [laserType] });
    if (path.startsWith('/api/v1/skills')) return Promise.resolve({ success: true, data: [skill] });
    if (path.startsWith('/api/v1/resources')) return Promise.resolve({ success: true, data: [resource] });
    return Promise.resolve({ success: true, data: [] });
  });
  post.mockResolvedValue({ success: true, data: resource });
}

describe('ResourcesPage', () => {
  beforeEach(() => vi.clearAllMocks());

  it('shows capacity as concurrency and both buffer minutes', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, { route: '/admin/resources' });

    await waitFor(() => expect(screen.getByText('لیزر ۱')).toBeInTheDocument());
    expect(screen.getByText('3 نفر')).toBeInTheDocument();
    expect(screen.getByText('5 / 10 دقیقه')).toBeInTheDocument();
  });

  it('labels a resource with no bridge as equipment', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, { route: '/admin/resources' });

    await waitFor(() => expect(screen.getByText(/تجهیزات/)).toBeInTheDocument());
  });

  it('renders each skill with its level', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, { route: '/admin/resources' });

    await waitFor(() => expect(screen.getByText('آلکساندرایت · 4')).toBeInTheDocument());
  });

  /**
   * فیلترها از URL خوانده می‌شوند و مستقیم به سرور می‌روند — فیلتر دوبارهٔ سمت
   * کلاینت روی فهرستی که خودش فیلترشده آمده، منبع اختلاف است.
   */
  it('passes the URL filters straight to the server', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, {
      route: '/admin/resources?address=b1&type=t1&skill=s1&status=1',
    });

    await waitFor(() => expect(get).toHaveBeenCalled());

    const called = get.mock.calls.map((c) => String(c[0]));
    const listCall = called.find((p) => p.startsWith('/api/v1/resources'));

    expect(listCall).toContain('address_uuid=b1');
    expect(listCall).toContain('type_uuid=t1');
    expect(listCall).toContain('skill_uuid=s1');
    expect(listCall).toContain('active=1');
  });

  it('sends address and type only when creating, never when editing', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, { route: '/admin/resources' });

    await waitFor(() => expect(screen.getByText('لیزر ۱')).toBeInTheDocument());

    fireEvent.click(screen.getByText('افزودن منبع'));
    fireEvent.change(screen.getByPlaceholderText('لیزر آلکساندرایت ۱'), { target: { value: 'لیزر تازه' } });

    // شعبه و نوع هنوز انتخاب نشده‌اند → ذخیره غیرفعال است.
    expect(screen.getByText('ذخیره').closest('button')).toBeDisabled();
  });

  /**
   * جدول فقط فهرست است. هر اقدامِ سطح-منبع تبی در خودِ منبع دارد، پس ردیف یک لینک
   * دارد نه شش دکمه — که هم جدول را از لبه بیرون می‌زد، هم یک کار را دو جا می‌گذاشت.
   */
  it('هر ردیف فقط یک اقدام دارد: مدیریتِ همان منبع', async () => {
    mockApi();
    renderWithProviders(<ResourcesPage />, { route: '/admin/resources' });

    await waitFor(() => expect(screen.getByText('لیزر ۱')).toBeInTheDocument());

    expect(screen.getAllByRole('link', { name: 'مدیریت' })[0])
      .toHaveAttribute('href', '/admin/resources/r1');

    for (const gone of ['ویرایش', 'مهارت‌ها', 'سرویس‌ها', 'مسدودسازی', 'حذف', 'تنظیمات']) {
      expect(screen.queryByRole('button', { name: gone })).not.toBeInTheDocument();
    }
  });
});
