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

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

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

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

vi.mock('@/services/recipes', () => ({
  getRecipe: mockGetRecipe,
  createRecipe: vi.fn(),
  updateRecipe: vi.fn(),
  listRecipes: vi.fn(),
  deleteRecipe: vi.fn(),
  scaleRecipe: vi.fn(),
  importRecipeFromText: vi.fn(),
  importRecipeFromUrl: vi.fn(),
  listRecipesByProduct: vi.fn(),
}));

vi.mock('next/navigation', () => ({
  useParams: () => ({ id: 'r1' }),
  useRouter: () => ({ push: vi.fn(), back: vi.fn() }),
}));

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

import EditRecipePage from '../../../../../../src/app/(dashboard)/recipes/[id]/edit/page';

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

const SAMPLE_RECIPE = {
  _id: 'r1',
  name: 'Pasta',
  description: '',
  servings: 4,
  tags: [],
  isFavorite: false,
  ingredients: [
    { productId: 'p1', productName: 'Flour', quantity: 200, unit: 'g', isOptional: false },
  ],
  steps: [{ order: 1, instruction: 'Mix' }],
  perServingNutrition: { calories: 200, protein: 5, carbs: 30, fat: 4 },
  totalNutrition: { calories: 800, protein: 20, carbs: 120, fat: 16 },
  warnings: [],
  createdBy: 'u1',
  createdAt: '2026-01-01T00:00:00.000Z',
  updatedAt: '2026-01-01T00:00:00.000Z',
  householdId: 'hh1',
};

describe('EditRecipePage', () => {
  it('shows loading state', () => {
    mockUseApi.mockReturnValue({ householdId: null, isLoading: true });

    render(<EditRecipePage />);

    expect(screen.getByText('Edit Recipe')).toBeInTheDocument();
    expect(screen.getByText('Loading...')).toBeInTheDocument();
  });

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

    render(<EditRecipePage />);

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

  it('renders editor when recipe loads', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockGetRecipe.mockResolvedValue(SAMPLE_RECIPE);

    render(<EditRecipePage />);

    await waitFor(() => {
      expect(screen.getByDisplayValue('Pasta')).toBeInTheDocument();
      expect(screen.getByText('Save changes')).toBeInTheDocument();
    });
  });

  it('shows fallback when recipe is not found', async () => {
    mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
    mockGetRecipe.mockRejectedValue('unexpected');

    render(<EditRecipePage />);

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