import { describe, it, expect, vi, beforeEach } from 'vitest';
import { screen, 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('react-router-dom', async () => ({
  ...(await vi.importActual<typeof import('react-router-dom')>('react-router-dom')),
  useParams: () => ({ courseUuid: 'c-1' }),
}));

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

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

const DAY = 86400;
const now = () => Math.floor(Date.now() / 1000);

function course(over: Record<string, unknown> = {}) {
  return {
    uuid: 'c-1',
    service_name: 'لیزر',
    status: 'active',
    min_days: 20,
    ideal_days: 28,
    max_days: 40,
    abandon_reason: null,
    preferred_resource_uuid: null,
    preferred_resource_name: null,
    progress: { completed: 1, booked: 0, planned: 1, total: 2 },
    sessions: [
      { session_number: 1, status: 'completed', slot_start: now() - 60 * DAY, completed_at: now() - 60 * DAY, params: {} },
      { session_number: 2, status: 'planned', slot_start: null, completed_at: null, params: {} },
    ],
    ...over,
  };
}

function mockCourse(payload: Record<string, unknown>) {
  get.mockImplementation((url: string) => {
    if (url.includes('next-slot-suggestion')) return Promise.resolve({ data: null });
    if (url.includes('/branch')) return Promise.resolve({ data: [] });
    return Promise.resolve({ data: payload });
  });
}

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

  /** ⭐ دوره‌ای که وسطش لغو شده بی‌صدا کِش می‌آید؛ هشدار نباید به انتخاب شعبه وابسته باشد. */
  it('warns when the course has run past the protocol maximum', async () => {
    mockCourse(course());

    renderWithProviders(<TreatmentCoursePage />);

    expect(await screen.findByText(/روز از آخرین جلسه گذشته/)).toBeInTheDocument();
  });

  it('stays quiet while the course is still inside its window', async () => {
    mockCourse(course({
      sessions: [
        { session_number: 1, status: 'completed', slot_start: now() - 5 * DAY, completed_at: now() - 5 * DAY, params: {} },
        { session_number: 2, status: 'planned', slot_start: null, completed_at: null, params: {} },
      ],
    }));

    renderWithProviders(<TreatmentCoursePage />);

    await waitFor(() => expect(get).toHaveBeenCalled());
    expect(screen.queryByText(/روز از آخرین جلسه گذشته/)).toBeNull();
  });

  /** فاصلهٔ واقعی، نه فاصلهٔ پروتکل — تفاوتشان همان چیزی است که کِش‌آمدن را نشان می‌دهد. */
  it('shows the real gap between two dated sessions', async () => {
    mockCourse(course({
      sessions: [
        { session_number: 1, status: 'completed', slot_start: now() - 40 * DAY, completed_at: now() - 40 * DAY, params: {} },
        { session_number: 2, status: 'completed', slot_start: now() - 10 * DAY, completed_at: now() - 10 * DAY, params: {} },
      ],
      progress: { completed: 2, booked: 0, planned: 0, total: 2 },
    }));

    renderWithProviders(<TreatmentCoursePage />);

    expect(await screen.findByText('۳۰ روز')).toBeInTheDocument();
  });
});
