// FE-COMP-MAP-001 to FE-COMP-MAP-017
import { render, screen, waitFor } from '../../../tests/helpers/render';
import userEvent from '@testing-library/user-event';
import { useAuthStore } from '../../store/authStore';
import { useSettingsStore } from '../../store/settingsStore';
import { resetAllStores, seedStore } from '../../../tests/helpers/store';
import { buildUser, buildSettings } from '../../../tests/helpers/factories';
import { ToastContainer } from '../shared/Toast';
import MapSettingsTab from './MapSettingsTab';

// Mock MapView to avoid Leaflet DOM issues in jsdom
vi.mock('../Map/MapView', () => ({
  MapView: ({ onMapClick }: { onMapClick?: (info: { latlng: { lat: number; lng: number } }) => void }) => (
    <div data-testid="map-view" onClick={() => onMapClick?.({ latlng: { lat: 51.5, lng: -0.1 } })} />
  ),
}));

beforeEach(() => {
  resetAllStores();
  vi.clearAllMocks();
  seedStore(useAuthStore, { user: buildUser(), isAuthenticated: true });
  seedStore(useSettingsStore, {
    settings: buildSettings({
      map_tile_url: '',
      default_lat: 48.8566,
      default_lng: 2.3522,
      default_zoom: 10,
    }),
    updateSettings: vi.fn().mockResolvedValue(undefined),
  });
});

describe('MapSettingsTab', () => {
  it('FE-COMP-MAP-001: renders without crashing', () => {
    render(<MapSettingsTab />);
    expect(document.body).toBeInTheDocument();
  });

  it('FE-COMP-MAP-002: shows the Map section title', () => {
    render(<MapSettingsTab />);
    expect(screen.getByText('Map')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-003: shows the map template label', () => {
    render(<MapSettingsTab />);
    expect(screen.getByText('Map Template')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-004: shows latitude and longitude inputs', () => {
    render(<MapSettingsTab />);
    expect(screen.getByText('Latitude')).toBeInTheDocument();
    expect(screen.getByText('Longitude')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-005: latitude input is pre-filled from store settings', () => {
    render(<MapSettingsTab />);
    expect(screen.getByDisplayValue('48.8566')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-006: longitude input is pre-filled from store settings', () => {
    render(<MapSettingsTab />);
    expect(screen.getByDisplayValue('2.3522')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-007: typing in the latitude input updates its displayed value', async () => {
    const user = userEvent.setup();
    render(<MapSettingsTab />);
    const latInput = screen.getByDisplayValue('48.8566');
    await user.clear(latInput);
    await user.type(latInput, '51.5');
    expect(screen.getByDisplayValue('51.5')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-008: typing in the longitude input updates its displayed value', async () => {
    const user = userEvent.setup();
    render(<MapSettingsTab />);
    const lngInput = screen.getByDisplayValue('2.3522');
    await user.clear(lngInput);
    await user.type(lngInput, '-0.1');
    expect(screen.getByDisplayValue('-0.1')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-009: tile URL text input is shown', () => {
    render(<MapSettingsTab />);
    const tileInput = screen.getByPlaceholderText(/openstreetmap/i);
    expect(tileInput).toBeInTheDocument();
  });

  it('FE-COMP-MAP-010: typing a custom tile URL updates the text input', async () => {
    const user = userEvent.setup();
    render(<MapSettingsTab />);
    const tileInput = screen.getByPlaceholderText(/openstreetmap/i);
    await user.clear(tileInput);
    // Escape curly braces so userEvent doesn't treat them as special keys
    await user.type(tileInput, 'https://custom.tiles/{{z}/{{x}/{{y}.png');
    expect(screen.getByDisplayValue('https://custom.tiles/{z}/{x}/{y}.png')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-011: clicking the Save Map button calls updateSettings', async () => {
    const user = userEvent.setup();
    const updateSettings = vi.fn().mockResolvedValue(undefined);
    seedStore(useSettingsStore, {
      settings: buildSettings({ map_tile_url: '', default_lat: 48.8566, default_lng: 2.3522, default_zoom: 10 }),
      updateSettings,
    });
    render(<MapSettingsTab />);
    await user.click(screen.getByText('Save Map'));
    expect(updateSettings).toHaveBeenCalledTimes(1);
    expect(updateSettings).toHaveBeenCalledWith(expect.objectContaining({
      map_tile_url: expect.any(String),
      default_lat: expect.any(Number),
      default_lng: expect.any(Number),
      default_zoom: expect.any(Number),
    }));
  });

  it('FE-COMP-MAP-012: Save Map parses numeric values correctly', async () => {
    const user = userEvent.setup();
    const updateSettings = vi.fn().mockResolvedValue(undefined);
    seedStore(useSettingsStore, {
      settings: buildSettings({ map_tile_url: '', default_lat: 48.8566, default_lng: 2.3522, default_zoom: 10 }),
      updateSettings,
    });
    render(<MapSettingsTab />);
    await user.click(screen.getByText('Save Map'));
    expect(updateSettings).toHaveBeenCalledWith(expect.objectContaining({
      map_tile_url: '',
      default_lat: 48.8566,
      default_lng: 2.3522,
      default_zoom: 10,
    }));
  });

  it('FE-COMP-MAP-013: Save Map button shows spinner while saving', async () => {
    const user = userEvent.setup();
    const updateSettings = vi.fn().mockReturnValue(new Promise(() => {}));
    seedStore(useSettingsStore, {
      settings: buildSettings(),
      updateSettings,
    });
    render(<MapSettingsTab />);
    await user.click(screen.getByText('Save Map'));
    const saveBtn = screen.getByText('Save Map').closest('button')!;
    expect(saveBtn).toBeDisabled();
  });

  it('FE-COMP-MAP-014: Save Map error shows a toast', async () => {
    const user = userEvent.setup();
    const updateSettings = vi.fn().mockRejectedValue(new Error('Save failed'));
    seedStore(useSettingsStore, {
      settings: buildSettings(),
      updateSettings,
    });
    render(<><ToastContainer /><MapSettingsTab /></>);
    await user.click(screen.getByText('Save Map'));
    await screen.findByText('Save failed');
  });

  it('FE-COMP-MAP-015: clicking the map updates lat/lng state', async () => {
    const user = userEvent.setup();
    render(<MapSettingsTab />);
    await user.click(screen.getByTestId('map-view'));
    await waitFor(() => {
      expect(screen.getByDisplayValue('51.5')).toBeInTheDocument();
      expect(screen.getByDisplayValue('-0.1')).toBeInTheDocument();
    });
  });

  it('FE-COMP-MAP-016: preset dropdown is rendered', () => {
    render(<MapSettingsTab />);
    expect(screen.getByText('Select template...')).toBeInTheDocument();
  });

  it('FE-COMP-MAP-017: settings update from store syncs local state', async () => {
    const { rerender } = render(<MapSettingsTab />);
    expect(screen.getByDisplayValue('48.8566')).toBeInTheDocument();

    seedStore(useSettingsStore, {
      settings: buildSettings({ default_lat: 40.0 }),
    });
    rerender(<MapSettingsTab />);

    await waitFor(() => {
      expect(screen.getByDisplayValue('40')).toBeInTheDocument();
    });
  });
});
