import {Pipe, PipeTransform} from '@angular/core';
import {SCThing, SCThings} from '@openstapps/core';
import {Feature, FeatureCollection, Point, Polygon} from 'geojson';

/**
 * Very simple hash function
 *
 * MapLibre cannot use strings as feature ids because of
 * vector tile spec limitations
 */
function simpleHash(value: string): number {
  let hash = 0;
  for (let i = 0; i < value.length; i++) {
    hash = Math.trunc((hash << 5) - hash + value.codePointAt(i)!);
  }
  return hash >>> 0;
}

/**
 * Finds the best name for a thing to display on the map
 */
function findBestName(thing: SCThing, targetLength = 14): string {
  if (!thing.alternateNames || thing.name.length <= targetLength) return thing.name;
  return thing.alternateNames.reduce(
    (accumulator, current) =>
      accumulator.length <= targetLength || accumulator.length <= current.length ? accumulator : current,
    thing.name,
  );
}

export interface SCFeatureProperties {
  name: string;
  category?: string;
  uid: string;
}

@Pipe({
  name: 'thingPoiFeatureCollection',
  standalone: true,
  pure: true,
})
export class ThingPoiFeatureCollectionPipe implements PipeTransform {
  transform(things: SCThings[]): FeatureCollection<Point, SCFeatureProperties> {
    return {
      type: 'FeatureCollection',
      features: things
        .filter(thing => 'geo' in thing && thing.geo.polygon === undefined)
        .map<Feature<Point, SCFeatureProperties>>(thing => ({
          type: 'Feature',
          properties: {
            name: findBestName(thing),
            category: 'categories' in thing ? thing.categories[0] : undefined,
            uid: thing.uid,
          },
          geometry: (thing as Extract<SCThings, {geo: object}>).geo.point,
          id: simpleHash(thing.uid),
        })),
    };
  }
}

@Pipe({
  name: 'thingPolygonFeatureCollection',
  standalone: true,
  pure: true,
})
export class ThingPolygonFeatureCollectionPipe implements PipeTransform {
  transform(things: SCThings[]): FeatureCollection<Polygon, SCFeatureProperties> {
    return {
      type: 'FeatureCollection',
      features: things
        .filter(thing => 'geo' in thing && thing.geo.polygon !== undefined)
        .map<Feature<Polygon, SCFeatureProperties>>(thing => ({
          type: 'Feature',
          geometry: (thing as Extract<SCThings, {geo: object}>).geo.polygon!,
          properties: {uid: thing.uid, name: findBestName(thing)},
          id: simpleHash(thing.uid),
        })),
    };
  }
}
