import { FieldType, type Segment } from "@hamradio/packet";

import { Frame } from "./frame";
import { DataType, type Payload, type ThirdPartyPayload, UserDefinedPayload } from "./frame.types";

export const decodeUserDefinedPayload = (
  raw: string,
  withStructure: boolean = false
): {
  payload: Payload | null;
  segment?: Segment[];
} => {
  try {
    if (raw.length < 2) return { payload: null };

    // content after '{'
    const rest = raw.substring(1);

    // user packet type is first token (up to first space) often like '01' or 'TYP'
    const match = rest.match(/^([^\s]+)\s*(.*)$/s);
    let userPacketType = "";
    let data = "";
    if (match) {
      userPacketType = match[1] || "";
      data = (match[2] || "").trim();
    }

    const payload: UserDefinedPayload = {
      type: DataType.UserDefined,
      userPacketType,
      data
    } as const;

    if (withStructure) {
      const segments: Segment[] = [];
      segments.push({
        name: "user-defined",
        data: new TextEncoder().encode(rest).buffer,
        isString: true,
        fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }]
      });

      segments.push({
        name: "user-packet-type",
        data: new TextEncoder().encode(userPacketType).buffer,
        isString: true,
        fields: [
          {
            type: FieldType.STRING,
            name: "type",
            length: userPacketType.length
          }
        ]
      });

      segments.push({
        name: "user-data",
        data: new TextEncoder().encode(data).buffer,
        isString: true,
        fields: [{ type: FieldType.STRING, name: "data", length: data.length }]
      });

      return { payload, segment: segments };
    }

    return { payload };
  } catch {
    return { payload: null };
  }
};

export const decodeThirdPartyPayload = (
  raw: string,
  withStructure: boolean = false
): {
  payload: Payload | null;
  segment?: Segment[];
} => {
  try {
    if (raw.length < 2) return { payload: null };

    // Content after '}' is the encapsulated third-party frame or raw data
    const rest = raw.substring(1);

    // Attempt to parse the embedded text as a full APRS frame (route:payload)
    let nestedFrame: Frame | undefined;
    try {
      // parseFrame is defined in this module; use Frame.parse to attempt parse
      nestedFrame = Frame.parse(rest);
    } catch {
      nestedFrame = undefined;
    }

    const payload: ThirdPartyPayload = {
      type: DataType.ThirdParty,
      comment: rest,
      ...(nestedFrame ? { frame: nestedFrame } : {})
    } as const;

    if (withStructure) {
      const segments: Segment[] = [];

      segments.push({
        name: "third-party",
        data: new TextEncoder().encode(rest).buffer,
        isString: true,
        fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }]
      });

      if (nestedFrame) {
        // Include a short section pointing to the nested frame's data (stringified)
        const nf = nestedFrame;
        const nfStr = `${nf.source.toString()}>${nf.destination.toString()}:${nf.payload}`;
        segments.push({
          name: "third-party-nested-frame",
          data: new TextEncoder().encode(nfStr).buffer,
          isString: true,
          fields: [
            {
              type: FieldType.STRING,
              name: "nested",
              length: nfStr.length
            }
          ]
        });
      }

      return { payload, segment: segments };
    }

    return { payload };
  } catch {
    return { payload: null };
  }
};
