// src/pages/admin/components/AddressForm.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AddressForm } from './AddressForm';
import type { Address } from '../../../types';

// Mock child components and icons to isolate the form's logic
vi.mock('lucide-react', () => ({
  MapPinIcon: () => <div data-testid="map-pin-icon" />,
}));

vi.mock('../../../components/LoadingSpinner', () => ({
  LoadingSpinner: () => <div data-testid="loading-spinner" />,
}));

describe('AddressForm', () => {
  const mockOnAddressChange = vi.fn();
  const mockOnGeocode = vi.fn();

  const defaultProps = {
    address: {},
    onAddressChange: mockOnAddressChange,
    onGeocode: mockOnGeocode,
    isGeocoding: false,
  };

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

  it('should render all address fields correctly', () => {
    render(<AddressForm {...defaultProps} />);

    expect(screen.getByRole('heading', { name: /home address/i })).toBeInTheDocument();
    expect(screen.getByLabelText(/address line 1/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/address line 2/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/city/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/province \/ state/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/postal \/ zip code/i)).toBeInTheDocument();
    expect(screen.getByLabelText(/country/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /re-geocode/i })).toBeInTheDocument();
  });

  it('should display values from the address prop', () => {
    const fullAddress: Partial<Address> = {
      address_line_1: '123 Main St',
      city: 'Anytown',
      country: 'Canada',
    };
    render(<AddressForm {...defaultProps} address={fullAddress} />);

    expect(screen.getByLabelText(/address line 1/i)).toHaveValue('123 Main St');
    expect(screen.getByLabelText(/city/i)).toHaveValue('Anytown');
    expect(screen.getByLabelText(/country/i)).toHaveValue('Canada');
  });

  it('should call onAddressChange with the correct field and value on input change', () => {
    render(<AddressForm {...defaultProps} />);

    const cityInput = screen.getByLabelText(/city/i);
    fireEvent.change(cityInput, { target: { value: 'New City' } });

    expect(mockOnAddressChange).toHaveBeenCalledTimes(1);
    expect(mockOnAddressChange).toHaveBeenCalledWith('city', 'New City');

    const postalInput = screen.getByLabelText(/postal \/ zip code/i);
    fireEvent.change(postalInput, { target: { value: 'A1B 2C3' } });

    expect(mockOnAddressChange).toHaveBeenCalledTimes(2);
    expect(mockOnAddressChange).toHaveBeenCalledWith('postal_code', 'A1B 2C3');
  });

  it('should call onGeocode when the "Re-Geocode" button is clicked', () => {
    render(<AddressForm {...defaultProps} />);

    const geocodeButton = screen.getByRole('button', { name: /re-geocode/i });
    fireEvent.click(geocodeButton);

    expect(mockOnGeocode).toHaveBeenCalledTimes(1);
  });

  describe('when isGeocoding is true', () => {
    it('should disable the button and show a loading spinner', () => {
      render(<AddressForm {...defaultProps} isGeocoding={true} />);

      const geocodeButton = screen.getByRole('button', { name: /re-geocode/i });
      expect(geocodeButton).toBeDisabled();

      // The button itself contains a spinner when loading
      expect(geocodeButton.querySelector('[data-testid="loading-spinner"]')).toBeInTheDocument();
      // A second spinner is shown next to the title
      expect(screen.getAllByTestId('loading-spinner')).toHaveLength(2);
    });
  });
});