import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';

const { mockUseApi } = vi.hoisted(() => ({
  mockUseApi: vi.fn(),
}));

const { mockListRegimens } = vi.hoisted(() => ({
  mockListRegimens: vi.fn(),
}));

vi.mock('@/lib/useApi', () => ({ useApi: mockUseApi }));

vi.mock('@/services/regimens', () => ({
  listRegimens: mockListRegimens,
}));

vi.mock('next/link', () => ({
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  default: (props: any) => <a href={props.href}>{props.children}</a>,
}));

import SchedulePage from '../../../../../src/app/(dashboard)/medicines/schedule/page';

beforeEach(() => vi.clearAllMocks());

const makeRegimen = (overrides = {}) => ({
  _id: 'reg1',
  householdId: 'hh1',
  name: 'Daily Vitamins',
  isActive: true,
  startDate: '2026-01-01',
  medications: [
    {
      medicineId: 'm1',
      medicineName: 'Vitamin D',
      medicineStrength: '1000',
      medicineStrengthUnit: 'IU',
      dosage: 1,
      dosageUnit: 'tablet',
      frequency: 'daily',
      timeOfDay: 'morning',
    },
  ],
  createdBy: 'u1',
  createdAt: '2026-01-01T00:00:00.000Z',
  updatedAt: '2026-01-01T00:00:00.000Z',
  ...overrides,
});

describe('SchedulePage', () => {
  it('shows loading skeleton when session is loading', () => {
    mockUseApi.mockReturnValue({ householdId: null, isLoading: true });

    render(<SchedulePage />);

    expect(screen.getByText('Schedule & Log')).toBeInTheDocument();
  });

  it('shows no household message', () => {
    mockUseApi.mockReturnValue({ householdId: null, isLoading: false });

    render(<SchedulePage />);

    expect(screen.getByText(/create or join a household/)).toBeInTheDocument();
  });

  it('shows empty state when no regimens', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('No active regimens found.')).toBeInTheDocument();
    });
  });

  it('shows set up link in empty state', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Set up a regimen')).toBeInTheDocument();
    });
  });

  it('renders medication in morning slot', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [makeRegimen()],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Vitamin D')).toBeInTheDocument();
      expect(screen.getByText('Morning')).toBeInTheDocument();
      expect(screen.getByText('1000 IU')).toBeInTheDocument();
      expect(screen.getByText('Daily Vitamins')).toBeInTheDocument();
    });
  });

  it('shows frequency label', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [makeRegimen()],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText(/Once daily/)).toBeInTheDocument();
    });
  });

  it('shows custom frequency', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [
        makeRegimen({
          medications: [
            {
              medicineId: 'm1',
              medicineName: 'Custom Med',
              medicineStrength: '50',
              medicineStrengthUnit: 'mg',
              dosage: 1,
              dosageUnit: 'tablet',
              frequency: 'custom',
              customFrequencyPerDay: 4,
              timeOfDay: 'morning',
            },
          ],
        }),
      ],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText(/4x daily/)).toBeInTheDocument();
    });
  });

  it('shows instructions when present', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [
        makeRegimen({
          medications: [
            {
              medicineId: 'm1',
              medicineName: 'Med A',
              medicineStrength: '10',
              medicineStrengthUnit: 'mg',
              dosage: 1,
              dosageUnit: 'pill',
              frequency: 'daily',
              timeOfDay: 'evening',
              instructions: 'Take with food',
            },
          ],
        }),
      ],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Take with food')).toBeInTheDocument();
      expect(screen.getByText('Evening')).toBeInTheDocument();
    });
  });

  it('shows dose count', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [makeRegimen()],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('1 dose')).toBeInTheDocument();
    });
  });

  it('shows error when fetch fails', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockRejectedValue(new Error('Network error'));

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Network error')).toBeInTheDocument();
    });
  });

  it('shows fallback error for non-Error failures', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockRejectedValue('unexpected');

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Failed to load regimens')).toBeInTheDocument();
    });
  });

  it('groups into "any" slot when timeOfDay is missing', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [
        makeRegimen({
          medications: [
            {
              medicineId: 'm2',
              medicineName: 'Aspirin',
              medicineStrength: '100',
              medicineStrengthUnit: 'mg',
              dosage: 1,
              dosageUnit: 'tablet',
              frequency: 'as_needed',
            },
          ],
        }),
      ],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Aspirin')).toBeInTheDocument();
      expect(screen.getByText('Any time')).toBeInTheDocument();
    });
  });

  it('paginates through regimens', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens
      .mockResolvedValueOnce({
        data: [makeRegimen()],
        pagination: { cursor: 'next', hasMore: true },
      })
      .mockResolvedValueOnce({
        data: [
          makeRegimen({
            _id: 'reg2',
            name: 'Second Regimen',
            medications: [
              {
                medicineId: 'm2',
                medicineName: 'Iron',
                medicineStrength: '65',
                medicineStrengthUnit: 'mg',
                dosage: 1,
                dosageUnit: 'tablet',
                frequency: 'daily',
                timeOfDay: 'afternoon',
              },
            ],
          }),
        ],
        pagination: { cursor: null, hasMore: false },
      });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText('Vitamin D')).toBeInTheDocument();
      expect(screen.getByText('Iron')).toBeInTheDocument();
    });
    expect(mockListRegimens).toHaveBeenCalledTimes(2);
  });

  it('shows regimen and dose summary', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockListRegimens.mockResolvedValue({
      data: [makeRegimen()],
      pagination: { cursor: null, hasMore: false },
    });

    render(<SchedulePage />);

    await waitFor(() => {
      expect(screen.getByText(/1 active regimen/)).toBeInTheDocument();
      expect(screen.getByText(/1 dose per day/)).toBeInTheDocument();
    });
  });
});
