import { EntrySource, EntryType, type UserSite } from 'src/types/timeTracking';
import { type SelectedSite } from 'src/utils/timeTracking';

import { REMOTE_WORK_SITE_VALUE } from '../../constants';

import { applyFormSiteOverride } from './applyFormSiteOverride';

const buildSite = (overrides: Partial<UserSite>): UserSite =>
  ({
    assignedAllUsers: false,
    createdAt: '',
    id: 1,
    body: null,
    location: {
      latitude: 10,
      longitude: 10,
      tolerance: 0,
      address: '',
    },
    name: 'Site',
    updatedAt: '',
    userIds: null,
    ...overrides,
  }) as UserSite;

// Base represents the entry the user actually clicked ("directSelectedSite").
// Its markingLocation is the real GPS coordinate where this specific entry was
// marked, and must never be replaced by another entry's coordinate.
const buildBase = (overrides: Partial<SelectedSite> = {}): SelectedSite => ({
  siteId: 1,
  siteName: 'Site A',
  location: { latitude: 10, longitude: 10, tolerance: 0, address: 'A' },
  markingLocation: { latitude: 99, longitude: 88 },
  entrySource: EntrySource.APP,
  entryType: EntryType.END,
  ...overrides,
});

describe('applyFormSiteOverride', () => {
  const sites = [
    buildSite({
      id: 1,
      name: 'Site A',
      location: { latitude: 10, longitude: 10, tolerance: 0, address: 'A' },
    }),
    buildSite({
      id: 2,
      name: 'Site B',
      location: { latitude: 20, longitude: 20, tolerance: 0, address: 'B' },
    }),
  ];

  it('returns null when there is no clicked entry', () => {
    expect(applyFormSiteOverride(null, 2, sites)).toBeNull();
  });

  it('preserves the clicked entry markingLocation/source/type when the site is reassigned during edit', () => {
    const base = buildBase();

    const result = applyFormSiteOverride(base, 2, sites);

    // Site fields reflect the new selection...
    expect(result?.siteId).toBe(2);
    expect(result?.siteName).toBe('Site B');
    expect(result?.location.latitude).toBe(20);
    // ...but the marking data still belongs to the clicked entry (the bug we fix).
    expect(result?.markingLocation).toEqual({ latitude: 99, longitude: 88 });
    expect(result?.entrySource).toBe(EntrySource.APP);
    expect(result?.entryType).toBe(EntryType.END);
  });

  it('returns the base unchanged when the form site matches the clicked entry site', () => {
    const base = buildBase({ siteId: 1 });
    expect(applyFormSiteOverride(base, 1, sites)).toBe(base);
  });

  it.each([
    undefined,
    0,
  ])('returns the base unchanged for a missing form value (%p)', formSiteId => {
    const base = buildBase();
    expect(applyFormSiteOverride(base, formSiteId, sites)).toBe(base);
  });

  it.each([
    -1,
    REMOTE_WORK_SITE_VALUE,
  ])('clears the site to the marking pin when the form value becomes "no site"/remote (%p)', formSiteId => {
    // Starts on a real site, then the dropdown is set to "no site"/remote.
    const base = buildBase({ siteId: 1, siteName: 'Site A' });

    const result = applyFormSiteOverride(base, formSiteId, sites);

    // Site is collapsed to the siteless state SiteMap renders as the pin only.
    expect(result?.siteId).toBe(-1);
    expect(result?.siteName).toBe('');
    // location is rebuilt from the marking coordinate (no tolerance ring)...
    expect(result?.location).toEqual({
      latitude: 99,
      longitude: 88,
      tolerance: 0,
      address: '',
    });
    // ...and the marking data still belongs to the clicked entry.
    expect(result?.markingLocation).toEqual({ latitude: 99, longitude: 88 });
    expect(result?.entrySource).toBe(EntrySource.APP);
    expect(result?.entryType).toBe(EntryType.END);
  });

  it('keeps the entry location when clearing a site with no marking coordinate', () => {
    const base = buildBase({ siteId: 1, markingLocation: null });

    const result = applyFormSiteOverride(base, -1, sites);

    expect(result?.siteId).toBe(-1);
    expect(result?.location).toEqual(base.location);
  });

  it('returns the base unchanged when it is already siteless and the form stays "no site"', () => {
    const base = buildBase({ siteId: -1 });
    expect(applyFormSiteOverride(base, -1, sites)).toBe(base);
  });

  it('returns the base unchanged when the form site is not found', () => {
    const base = buildBase();
    expect(applyFormSiteOverride(base, 999, sites)).toBe(base);
  });
});
