// **** RESOURCE CLASSES **********

import {
  LineStringFeature,
  PointFeature,
  PolygonFeature,
  MultiPolygonFeature,
  MultiLineStringFeature,
  Position,
  TrackResource,
  SKPosition,
  RouteResource,
  WaypointResource,
  RegionResource,
  NoteResource,
  ChartResource,
  ChartImageAdjustment
} from 'src/app/types';

// ** Signal K route class
export class SKRoute {
  name: string;
  description: string;
  distance = 0;
  feature: LineStringFeature;

  constructor(route?: RouteResource) {
    this.name = route?.name ? route.name : '';
    this.description = route?.description ? route.description : '';
    this.distance = route?.distance ? route.distance : 0;
    this.feature = route?.feature ?? {
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: []
      },
      properties: {},
      id: ''
    };
  }
}

// ** Signal K waypoint
export class SKWaypoint {
  name: string;
  description: string;
  feature: PointFeature;
  type: string;

  constructor(wpt?: WaypointResource) {
    this.name = wpt?.name ? wpt.name : '';
    this.description = wpt?.description ? wpt.description : '';
    this.type = wpt?.type ? wpt.type : '';
    this.feature = wpt?.feature ?? {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0]
      },
      properties: {},
      id: ''
    };
  }
}

// ** Signal K Note
export class SKNote {
  name: string;
  description: string;
  position: SKPosition;
  href: string;
  mimeType: string;
  url: string;
  group: string;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  authors: Array<any>;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  properties: Record<string, any>;

  constructor(note?: NoteResource) {
    this.name = note?.name ?? '';
    this.description = note?.description ?? '';
    this.position = note?.position;
    this.href = note?.href;
    this.mimeType = note?.mimeType ?? '';
    this.url = note?.url ?? '';
    // ca reports
    this.group = note?.group;
    this.authors =
      note?.authors && Array.isArray(note?.authors) ? note.authors : [];
    this.properties =
      note?.properties && typeof note?.properties === 'object'
        ? note.properties
        : {};
  }
}

// ** Signal K Region **
export class SKRegion {
  name: string;
  description: string;
  feature: PolygonFeature | MultiPolygonFeature;

  constructor(region?: RegionResource) {
    this.name = region?.name ? region.name : '';
    this.description = region?.description ? region.description : '';
    this.feature = region?.feature ?? {
      type: 'Feature',
      geometry: {
        type: 'Polygon',
        coordinates: []
      },
      properties: {},
      id: ''
    };
  }
}

// ** Signal K chart
export class SKChart {
  identifier: string;
  name: string;
  description: string;
  region: string;
  scale = 250000;
  layers: Array<string>;
  bounds: Array<number>;
  format: string;
  minZoom = 0;
  maxZoom = 24;
  tileSize = 256;
  type: string;
  url: string;
  source: string;
  style: string;
  defaultOpacity: number;
  imageAdjustment?: ChartImageAdjustment;
  displayMinZoom?: number;
  proxy: boolean;

  // Accepts a server chart resource or an existing SKChart: the chart cache
  // re-constructs an entry from an instance to trigger a re-render, and the
  // instance spells these three fields differently to the resource.
  constructor(chart?: ChartResource | SKChart) {
    const src = chart as (ChartResource & SKChart) | undefined;
    this.identifier = chart?.identifier ? chart.identifier : undefined;
    this.name = chart?.name ? chart.name : undefined;
    this.description = chart?.description ? chart.description : undefined;
    this.layers = chart?.layers ? chart.layers : [];
    this.bounds = chart?.bounds ? chart.bounds : undefined;
    this.format = chart?.format ? chart.format : undefined;
    this.minZoom = src?.minzoom ?? src?.minZoom ?? this.minZoom;
    this.maxZoom = src?.maxzoom ?? src?.maxZoom ?? this.maxZoom;
    this.tileSize =
      typeof chart?.tileSize !== 'undefined' ? chart.tileSize : this.tileSize;
    this.type = chart?.type ? chart.type : undefined;
    this.url = chart?.url ? chart.url : undefined;
    this.scale =
      typeof chart?.scale !== 'undefined' && !isNaN(chart?.scale)
        ? chart.scale
        : this.scale;
    this.style = chart?.style ?? undefined;
    this.source = src?.$source ?? src?.source ?? undefined;
    this.defaultOpacity = chart?.defaultOpacity ?? 1;
    this.imageAdjustment = chart?.imageAdjustment;
    this.displayMinZoom = chart?.displayMinZoom;
    this.proxy = chart?.proxy ?? false;
  }
}

// ** Signal K Track
export class SKTrack {
  name: string;
  description: string;
  feature: MultiLineStringFeature;

  constructor(trk?: TrackResource) {
    this.feature = trk?.feature ?? {
      type: 'Feature',
      geometry: {
        type: 'MultiLineString',
        coordinates: []
      },
      properties: {},
      id: ''
    };
    this.name = this.feature.properties?.name ?? '';
    this.description = this.feature.properties?.description ?? '';
  }
}

// ** SK Target Base class **
class SKTargetBase {
  id: string;
  name: string;
  mmsi: string;
  position: Position = [0, 0];
  positionReceived = false;
  positionTimestamp: string = '';
  /** Client-clock epoch ms at which the last position delta was received
   * (0 = none yet). Stamped locally rather than derived from
   * `positionTimestamp` so position age is immune to server clock skew. */
  positionUpdatedAt = 0;
  state: string;
  type: { id: number; name: string } = { id: -1, name: '' };
  properties: { [key: string]: any } = {};
  lastUpdated = new Date();
  callsignVhf: string;
  callsignHf: string;
  orientation = 0;
  virtual?: boolean;
}

// ** Vessel Data **
export class SKVessel extends SKTargetBase {
  // stream sourced attributes
  anchor = { maxRadius: null, radius: null, position: null };
  autopilot = {
    state: null,
    mode: null,
    target: null,
    enabled: false,
    default: null,
    availableActions: []
  };
  buddy = false;
  closestApproach = {
    distance: null,
    timeTo: null
  };
  cog: number;
  cogTrue: number = null;
  cogMagnetic: number = null;
  courseApi = {
    arrivalCircle: 0,
    activeRoute: {},
    nextPoint: {},
    previousPoint: {}
  };
  courseCalcs: Record<string, any> = {};
  distanceToSelf: number;
  environment = {
    mode: null, // day | night
    sun: null // dawn| sunrise | day | sunset | dusk | night
  };
  heading: number;
  headingTrue: number = null;
  headingMagnetic: number = null;
  performance = {
    beatAngle: null,
    gybeAngle: null
  };
  racing: Record<string, any>;
  radars: Record<string, any> = {};
  registrations: Record<string, any> = {};
  resourceUpdates = []; // resource deltas
  sog: number;
  track: Array<Position[]> = [];
  vectors = {
    cog: [] // cog vector
  };
  wind = {
    direction: null,
    mwd: null,
    twd: null,
    tws: null,
    speedTrue: null,
    sog: null,
    awa: null,
    aws: null
  };

  // http api sourced attributes
  design = {
    airHeight: null,
    beam: null,
    draft: {
      current: null,
      maximum: null
    },
    length: null
  };
  destination = {
    name: null,
    eta: null
  };
  flag: string;
  port: string;
}

// ** SaR class **
export class SKSaR extends SKTargetBase {
  constructor() {
    super();
  }
}

// ** Aircraft Data **
export class SKAircraft extends SKTargetBase {
  sog = 0;
  track: Array<Position[]> = [];
  constructor() {
    super();
  }
}

// ** AtoN class **
export class SKAtoN extends SKTargetBase {
  constructor() {
    super();
  }
}

// ** Meteo / weather class **
export class SKMeteo extends SKAtoN {
  twd: number;
  tws: number;
  temperature: number;
  constructor() {
    super();
  }
}
