import { PacketSegment, PacketStructure } from "./parser.types";

export interface IAddress {
  call:       string;
  ssid:       string;
  isRepeated: boolean;
}

export interface IFrame {
  source:      IAddress;
  destination: IAddress;
  path:        IAddress[];
  payload:     string;
}

// APRS Data Type Identifiers (first character of payload)
export const DataTypeIdentifier = {
  // Position Reports
  PositionNoTimestampNoMessaging: '!',
  PositionNoTimestampWithMessaging: '=',
  PositionWithTimestampNoMessaging: '/',
  PositionWithTimestampWithMessaging: '@',

  // Mic-E
  MicECurrent: '`',
  MicEOld: "'",

  // Messages and Bulletins
  Message: ':',

  // Objects and Items
  Object: ';',
  Item: ')',

  // Status
  Status: '>',

  // Query
  Query: '?',

  // Telemetry
  TelemetryData: 'T',

  // Weather
  WeatherReportNoPosition: '_',

  // Raw GPS Data
  RawGPS: '$',

  // Station Capabilities
  StationCapabilities: '<',

  // User-Defined
  UserDefined: '{',

  // Third-Party Traffic
  ThirdParty: '}',

  // Invalid/Test Data
  InvalidOrTest: ',',
} as const;

export type DataTypeIdentifier = typeof DataTypeIdentifier[keyof typeof DataTypeIdentifier];

export interface ISymbol {
  table: string;    // Symbol table identifier
  code: string;     // Symbol code

  toString(): string; // Return combined symbol representation (e.g., "tablecode")
}

// Position data common to multiple formats
export interface 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?: ISymbol;
  comment?: string;

  toString(): string; // Return combined position representation (e.g., "lat,lon,alt")
  toCompressed?(): CompressedPosition; // Optional method to convert to compressed format
  distanceTo?(other: IPosition): number; // Optional method to calculate distance to another position
}

export interface ITimestamp {
  day?: number;       // Day of month (DHM format)
  month?: number;     // Month (MDHM format)
  hours: number;
  minutes: number;
  seconds?: number;
  format: 'DHM' | 'HMS' | 'MDHM'; // Day-Hour-Minute, Hour-Minute-Second, Month-Day-Hour-Minute
  zulu?: boolean;     // Is UTC/Zulu time
  toDate(): Date;     // Convert to Date object respecting timezone
}

// Position Report Payload
export interface PositionPayload {
  type: 'position';
  timestamp?: ITimestamp;
  position: IPosition;
  messaging: boolean;  // Whether APRS messaging is enabled
  micE?: {
    messageType?: string;
    isStandard?: boolean;
  };
  sections?: PacketSegment[];
}

// Compressed Position Format
export interface CompressedPosition {
  latitude: number;
  longitude: number;
  symbol: {
    table: string;
    code: string;
  };
  course?: number;     // Degrees
  speed?: number;      // Knots
  range?: number;      // Miles
  altitude?: number;   // Feet
  radioRange?: number; // Miles
  compression: 'old' | 'current';
}

// Mic-E Payload (compressed in destination address)
export interface MicEPayload {
  type: 'mic-e';
  position: IPosition;
  course?: number;
  speed?: number;
  altitude?: number;
  messageType?: string;  // Standard Mic-E message
  telemetry?: number[];  // Optional telemetry channels
  status?: string;
}

// Message Payload
export interface MessagePayload {
  type: 'message';
  addressee: string;   // 9 character padded callsign
  text: string;        // Message text
  messageNumber?: string;  // Message ID for acknowledgment
  ack?: string;        // Acknowledgment of message ID
  reject?: string;     // Rejection of message ID
}

// Bulletin/Announcement (variant of message)
export interface BulletinPayload {
  type: 'bulletin';
  bulletinId: string;  // Bulletin identifier (BLN#)
  text: string;
  group?: string;      // Optional group bulletin
}

// Object Payload
export interface ObjectPayload {
  type: 'object';
  name: string;        // 9 character object name
  timestamp: ITimestamp;
  alive: boolean;      // True if object is active, false if killed
  position: IPosition;
  course?: number;
  speed?: number;
}

// Item Payload
export interface ItemPayload {
  type: 'item';
  name: string;        // 3-9 character item name
  alive: boolean;      // True if item is active, false if killed
  position: IPosition;
}

// Status Payload
export interface StatusPayload {
  type: 'status';
  timestamp?: ITimestamp;
  text: string;
  maidenhead?: string; // Optional Maidenhead grid locator
  symbol?: {
    table: string;
    code: string;
  };
}

// Query Payload
export interface QueryPayload {
  type: 'query';
  queryType: string;   // e.g., 'APRSD', 'APRST', 'PING'
  target?: string;     // Target callsign or area
}

// Telemetry Data Payload
export interface TelemetryDataPayload {
  type: 'telemetry-data';
  sequence: number;
  analog: number[];    // Up to 5 analog channels
  digital: number;     // 8-bit digital value
}

// Telemetry Parameter Names
export interface TelemetryParameterPayload {
  type: 'telemetry-parameters';
  names: string[];     // Parameter names
}

// Telemetry Unit/Label
export interface TelemetryUnitPayload {
  type: 'telemetry-units';
  units: string[];     // Units for each parameter
}

// Telemetry Coefficients
export interface TelemetryCoefficientsPayload {
  type: 'telemetry-coefficients';
  coefficients: {
    a: number[];       // a coefficients
    b: number[];       // b coefficients
    c: number[];       // c coefficients
  };
}

// Telemetry Bit Sense/Project Name
export interface TelemetryBitSensePayload {
  type: 'telemetry-bitsense';
  sense: number;       // 8-bit sense value
  projectName?: string;
}

// Weather Report Payload
export interface WeatherPayload {
  type:                'weather';
  timestamp?:          ITimestamp;
  position?:           IPosition;
  windDirection?:      number;   // Degrees
  windSpeed?:          number;   // MPH
  windGust?:           number;   // MPH
  temperature?:        number;   // Fahrenheit
  rainLastHour?:       number;   // Hundredths of inch
  rainLast24Hours?:    number;   // Hundredths of inch
  rainSinceMidnight?:  number;   // Hundredths of inch
  humidity?:           number;   // Percent
  pressure?:           number;   // Tenths of millibar
  luminosity?:         number;   // Watts per square meter
  snowfall?:           number;   // Inches
  rawRain?:            number;   // Raw rain counter
  software?:           string;   // Weather software type
  weatherUnit?:        string;   // Weather station type
}

// Raw GPS Payload (NMEA sentences)
export interface RawGPSPayload {
  type: 'raw-gps';
  sentence: string;    // Raw NMEA sentence
}

// Station Capabilities Payload
export interface StationCapabilitiesPayload {
  type: 'capabilities';
  capabilities: string[];
}

// User-Defined Payload
export interface UserDefinedPayload {
  type: 'user-defined';
  userPacketType: string;
  data: string;
}

// Third-Party Traffic Payload
export interface ThirdPartyPayload {
  type: 'third-party';
  header: string;      // Source path of third-party packet
  payload: string;     // Nested APRS packet
}

// DF Report Payload
export interface DFReportPayload {
  type: 'df-report';
  timestamp?: ITimestamp;
  position: IPosition;
  course?: number;
  bearing?: number;    // Direction finding bearing
  quality?: number;    // Signal quality
  strength?: number;   // Signal strength
  height?: number;     // Antenna height
  gain?: number;       // Antenna gain
  directivity?: string; // Antenna directivity pattern
}

export interface BasePayload {
  type: string;
}

// Union type for all decoded payload types
export type Payload = BasePayload & (
  | PositionPayload
  | MicEPayload
  | MessagePayload
  | BulletinPayload
  | ObjectPayload
  | ItemPayload
  | StatusPayload
  | QueryPayload
  | TelemetryDataPayload
  | TelemetryParameterPayload
  | TelemetryUnitPayload
  | TelemetryCoefficientsPayload
  | TelemetryBitSensePayload
  | WeatherPayload
  | RawGPSPayload
  | StationCapabilitiesPayload
  | UserDefinedPayload
  | ThirdPartyPayload
  | DFReportPayload
);

// Extended Frame with decoded payload
export interface DecodedFrame extends IFrame {
  decoded?:   Payload;
  structure?: PacketStructure; // Routing and other frame-level sections
}
