import {
  CITY_DEFINITIONS,
  isShowAllBrowseArea,
  parseServiceArea,
  serviceAreasForFilter,
  SERVICE_AREA_COORDINATES,
  SERVICE_AREA_LABELS,
  type ServiceArea,
} from '@ehandyhire/shared';

export const PHILIPPINES_CENTER = { lat: 12.8797, lng: 121.774 };
export const MINDANAO_CENTER = SERVICE_AREA_COORDINATES.ENTIRE_MINDANAO;
export const DAVAO_REGION_CENTER = SERVICE_AREA_COORDINATES.ENTIRE_DAVAO_REGION;

export const AREA_COORDINATES = SERVICE_AREA_COORDINATES;
export const AREA_LABELS = SERVICE_AREA_LABELS;

/** City/area options for location pickers (excludes region-wide entries). */
export const SERVICE_AREA_OPTIONS = CITY_DEFINITIONS.map((c) => ({
  value: c.key,
  label: c.label,
}));

export const WORKER_SERVICE_AREA_OPTIONS = SERVICE_AREA_OPTIONS;

export type ServiceAreaKey = keyof typeof AREA_COORDINATES;

const WORKER_SELECTABLE_SET = new Set(
  WORKER_SERVICE_AREA_OPTIONS.map((opt) => opt.value)
);

export function normalizeWorkerServiceAreas(areas: ServiceAreaKey[]): ServiceAreaKey[] {
  const filtered = areas.filter((area) => WORKER_SELECTABLE_SET.has(area));
  return filtered.length > 0 ? filtered : ['DAVAO_CITY'];
}

function distanceSq(lat1: number, lng1: number, lat2: number, lng2: number) {
  const dLat = lat1 - lat2;
  const dLng = lng1 - lng2;
  return dLat * dLat + dLng * dLng;
}

/** Pick the closest service area for a GPS point. */
export function findNearestServiceArea(lat: number, lng: number): ServiceAreaKey {
  let nearest: ServiceAreaKey = 'DAVAO_CITY';
  let min = Infinity;
  for (const city of CITY_DEFINITIONS) {
    const d = distanceSq(lat, lng, city.lat, city.lng);
    if (d < min) {
      min = d;
      nearest = city.key as ServiceAreaKey;
    }
  }
  return nearest;
}

const LOCATION_ALIASES: Record<string, ServiceAreaKey> = Object.fromEntries(
  CITY_DEFINITIONS.flatMap((c) => {
    const entries: [string, ServiceAreaKey][] = [
      [c.label.toLowerCase(), c.key as ServiceAreaKey],
      [c.slug.replace(/-/g, ' '), c.key as ServiceAreaKey],
    ];
    return entries;
  })
) as Record<string, ServiceAreaKey>;

Object.assign(LOCATION_ALIASES, {
  manila: 'MANILA',
  qc: 'QUEZON_CITY',
  'quezon city': 'QUEZON_CITY',
  cebu: 'CEBU_CITY',
  'cebu city': 'CEBU_CITY',
  davao: 'DAVAO_CITY',
  'davao city': 'DAVAO_CITY',
  gensan: 'GENERAL_SANTOS',
  'general santos': 'GENERAL_SANTOS',
  'cagayan de oro': 'CAGAYAN_DE_ORO',
  cdo: 'CAGAYAN_DE_ORO',
  iligan: 'ILIGAN_CITY',
  zamboanga: 'ZAMBOANGA_CITY',
  bacolod: 'BACOLOD',
  iloilo: 'ILOILO_CITY',
  baguio: 'BAGUIO',
  angeles: 'ANGELES',
  antipolo: 'ANTIPOLO',
  philippines: 'ENTIRE_PHILIPPINES',
  luzon: 'ENTIRE_LUZON',
  visayas: 'ENTIRE_VISAYAS',
  mindanao: 'ENTIRE_MINDANAO',
  'entire mindanao': 'ENTIRE_MINDANAO',
  ncr: 'ENTIRE_NCR',
  'metro manila': 'ENTIRE_NCR',
  'davao region': 'ENTIRE_DAVAO_REGION',
});

function hashToOffset(id: string, scale = 0.012): { lat: number; lng: number } {
  let hash = 0;
  for (let i = 0; i < id.length; i++) {
    hash = id.charCodeAt(i) + ((hash << 5) - hash);
  }
  return {
    lat: ((hash % 100) / 100 - 0.5) * scale,
    lng: (((hash >> 8) % 100) / 100 - 0.5) * scale,
  };
}

export function geocodeLocation(location: string): { lat: number; lng: number } | null {
  const normalized = location.trim().toLowerCase();
  const areaKey = LOCATION_ALIASES[normalized];
  if (areaKey) return AREA_COORDINATES[areaKey];

  for (const [alias, key] of Object.entries(LOCATION_ALIASES)) {
    if (normalized.includes(alias)) return AREA_COORDINATES[key];
  }

  return null;
}

export function resolveJobCoordinates(job: {
  id: string;
  location: string;
  latitude?: number | null;
  longitude?: number | null;
}): { lat: number; lng: number } | null {
  if (job.latitude != null && job.longitude != null) {
    return { lat: job.latitude, lng: job.longitude };
  }
  const geocoded = geocodeLocation(job.location);
  if (!geocoded) return null;
  const offset = hashToOffset(job.id, 0.004);
  return { lat: geocoded.lat + offset.lat, lng: geocoded.lng + offset.lng };
}

export function resolveWorkerPinArea(
  serviceAreas: { area: string }[] | undefined,
  browseRegionSlug?: string | null
): string {
  const areas = serviceAreas?.map((a) => a.area).filter(Boolean) ?? [];
  if (areas.length === 0) return 'DAVAO_CITY';

  const browseArea = browseRegionSlug ? parseServiceArea(browseRegionSlug) : null;
  if (!browseArea || isShowAllBrowseArea(browseArea)) return areas[0];

  if (areas.includes(browseArea)) return browseArea;

  const filterAreas = new Set(serviceAreasForFilter(browseArea));
  const matched = areas.find((a) => filterAreas.has(a as ServiceArea));
  return matched ?? areas[0];
}

export function resolveWorkerAreaLabel(
  serviceAreas: { area: string }[] | undefined,
  browseRegionSlug?: string | null
): string {
  const area = resolveWorkerPinArea(serviceAreas, browseRegionSlug);
  return AREA_LABELS[area] || area;
}

export function resolveWorkerCoordinates(
  worker: {
    id: string;
    serviceAreas?: { area: string }[];
  },
  browseRegionSlug?: string | null
): { lat: number; lng: number } {
  const area = resolveWorkerPinArea(worker.serviceAreas, browseRegionSlug);
  const base = AREA_COORDINATES[area] || PHILIPPINES_CENTER;
  const offset = hashToOffset(worker.id);
  return { lat: base.lat + offset.lat, lng: base.lng + offset.lng };
}

export function resolveWorkerAreaPins(worker: {
  id: string;
  serviceAreas?: { area: string }[];
}): { lat: number; lng: number; label: string }[] {
  const areas = worker.serviceAreas?.length
    ? worker.serviceAreas
    : [{ area: 'DAVAO_CITY' }];

  return areas.map((a, index) => {
    const base = AREA_COORDINATES[a.area] || PHILIPPINES_CENTER;
    const offset = hashToOffset(`${worker.id}-${a.area}`, 0.006);
    return {
      lat: base.lat + offset.lat + index * 0.001,
      lng: base.lng + offset.lng,
      label: AREA_LABELS[a.area] || a.area,
    };
  });
}
