import { IPosition, ISymbol } from "./frame.types";

export class Symbol implements ISymbol {
  table: string;    // Symbol table identifier
  code: string;     // Symbol code

  constructor(table: string, code?: string) {
    if (code === undefined) {
      if (table.length === 2) {
        this.code = table[1];
        this.table = table[0];
      } else {
        throw new Error(`Invalid symbol format: '${table}' (expected 2 characters if code is not provided)`);
      }
    } else {
      this.table = table;
      this.code = code;
    }
  }

  public toString(): string {
    return `${this.table}${this.code}`;
  }
}

export class Position implements IPosition {
  latitude: number;   // Decimal degrees
  longitude: number;  // Decimal degrees
  ambiguity?: number; // Position ambiguity (0-4)
  altitude?: number;  // Meters
  speed?: number;     // Speed in knots/kmh depending on source
  course?: number;    // Course in degrees
  symbol?: Symbol;
  comment?: string;

  constructor(data: Partial<IPosition>) {
    this.latitude = data.latitude ?? 0;
    this.longitude = data.longitude ?? 0;
    this.ambiguity = data.ambiguity;
    this.altitude = data.altitude;
    this.speed = data.speed;
    this.course = data.course;
    if (typeof data.symbol === 'string') {
      this.symbol = new Symbol(data.symbol);
    } else if (data.symbol) {
      this.symbol = new Symbol(data.symbol.table, data.symbol.code);
    }
    this.comment = data.comment;
  }

  public toString(): string {
    const latStr = this.latitude.toFixed(5);
    const lonStr = this.longitude.toFixed(5);
    const altStr = this.altitude !== undefined ? `,${this.altitude}m` : '';
    return `${latStr},${lonStr}${altStr}`;
  }

  public distanceTo(other: IPosition): number {
    const R = 6371e3; // Earth radius in meters
    const lat1 = this.latitude * Math.PI / 180;
    const lat2 = other.latitude * Math.PI / 180;
    const dLat = (other.latitude - this.latitude) * Math.PI / 180;
    const dLon = (other.longitude - this.longitude) * Math.PI / 180;

    const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.cos(lat1) * Math.cos(lat2) *
          Math.sin(dLon/2) * Math.sin(dLon/2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    return R * c; // Distance in meters
  }
}
