import { normalizeE164 } from "../utils.js";

export type IMessageService = "imessage" | "sms" | "auto";

export type IMessageTarget =
  | { kind: "chat_id"; chatId: number }
  | { kind: "chat_guid"; chatGuid: string }
  | { kind: "chat_identifier"; chatIdentifier: string }
  | { kind: "handle"; to: string; service: IMessageService };

export type IMessageAllowTarget =
  | { kind: "chat_id"; chatId: number }
  | { kind: "chat_guid"; chatGuid: string }
  | { kind: "chat_identifier"; chatIdentifier: string }
  | { kind: "handle"; handle: string };

const CHAT_ID_PREFIXES = ["chat_id:", "chatid:", "chat:"];
const CHAT_GUID_PREFIXES = ["chat_guid:", "chatguid:", "guid:"];
const CHAT_IDENTIFIER_PREFIXES = ["chat_identifier:", "chatidentifier:", "chatident:"];
const SERVICE_PREFIXES: Array<{ prefix: string; service: IMessageService }> = [
  { prefix: "imessage:", service: "imessage" },
  { prefix: "sms:", service: "sms" },
  { prefix: "auto:", service: "auto" },
];

function stripPrefix(value: string, prefix: string): string {
  return value.slice(prefix.length).trim();
}

export function normalizeIMessageHandle(raw: string): string {
  const trimmed = raw.trim();
  if (!trimmed) {
    return "";
  }
  const lowered = trimmed.toLowerCase();
  if (lowered.startsWith("imessage:")) {
    return normalizeIMessageHandle(trimmed.slice(9));
  }
  if (lowered.startsWith("sms:")) {
    return normalizeIMessageHandle(trimmed.slice(4));
  }
  if (lowered.startsWith("auto:")) {
    return normalizeIMessageHandle(trimmed.slice(5));
  }

  // Normalize chat_id/chat_guid/chat_identifier prefixes case-insensitively
  for (const prefix of CHAT_ID_PREFIXES) {
    if (lowered.startsWith(prefix)) {
      const value = trimmed.slice(prefix.length).trim();
      return `chat_id:${value}`;
    }
  }
  for (const prefix of CHAT_GUID_PREFIXES) {
    if (lowered.startsWith(prefix)) {
      const value = trimmed.slice(prefix.length).trim();
      return `chat_guid:${value}`;
    }
  }
  for (const prefix of CHAT_IDENTIFIER_PREFIXES) {
    if (lowered.startsWith(prefix)) {
      const value = trimmed.slice(prefix.length).trim();
      return `chat_identifier:${value}`;
    }
  }

  if (trimmed.includes("@")) {
    return trimmed.toLowerCase();
  }
  const normalized = normalizeE164(trimmed);
  if (normalized) {
    return normalized;
  }
  return trimmed.replace(/\s+/g, "");
}

export function parseIMessageTarget(raw: string): IMessageTarget {
  const trimmed = raw.trim();
  if (!trimmed) {
    throw new Error("iMessage target is required");
  }
  const lower = trimmed.toLowerCase();

  for (const { prefix, service } of SERVICE_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const remainder = stripPrefix(trimmed, prefix);
      if (!remainder) {
        throw new Error(`${prefix} target is required`);
      }
      const remainderLower = remainder.toLowerCase();
      const isChatTarget =
        CHAT_ID_PREFIXES.some((p) => remainderLower.startsWith(p)) ||
        CHAT_GUID_PREFIXES.some((p) => remainderLower.startsWith(p)) ||
        CHAT_IDENTIFIER_PREFIXES.some((p) => remainderLower.startsWith(p));
      if (isChatTarget) {
        return parseIMessageTarget(remainder);
      }
      return { kind: "handle", to: remainder, service };
    }
  }

  for (const prefix of CHAT_ID_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      const chatId = Number.parseInt(value, 10);
      if (!Number.isFinite(chatId)) {
        throw new Error(`Invalid chat_id: ${value}`);
      }
      return { kind: "chat_id", chatId };
    }
  }

  for (const prefix of CHAT_GUID_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      if (!value) {
        throw new Error("chat_guid is required");
      }
      return { kind: "chat_guid", chatGuid: value };
    }
  }

  for (const prefix of CHAT_IDENTIFIER_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      if (!value) {
        throw new Error("chat_identifier is required");
      }
      return { kind: "chat_identifier", chatIdentifier: value };
    }
  }

  return { kind: "handle", to: trimmed, service: "auto" };
}

export function parseIMessageAllowTarget(raw: string): IMessageAllowTarget {
  const trimmed = raw.trim();
  if (!trimmed) {
    return { kind: "handle", handle: "" };
  }
  const lower = trimmed.toLowerCase();

  for (const { prefix } of SERVICE_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const remainder = stripPrefix(trimmed, prefix);
      if (!remainder) {
        return { kind: "handle", handle: "" };
      }
      return parseIMessageAllowTarget(remainder);
    }
  }

  for (const prefix of CHAT_ID_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      const chatId = Number.parseInt(value, 10);
      if (Number.isFinite(chatId)) {
        return { kind: "chat_id", chatId };
      }
    }
  }

  for (const prefix of CHAT_GUID_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      if (value) {
        return { kind: "chat_guid", chatGuid: value };
      }
    }
  }

  for (const prefix of CHAT_IDENTIFIER_PREFIXES) {
    if (lower.startsWith(prefix)) {
      const value = stripPrefix(trimmed, prefix);
      if (value) {
        return { kind: "chat_identifier", chatIdentifier: value };
      }
    }
  }

  return { kind: "handle", handle: normalizeIMessageHandle(trimmed) };
}

export function isAllowedIMessageSender(params: {
  allowFrom: Array<string | number>;
  sender: string;
  chatId?: number | null;
  chatGuid?: string | null;
  chatIdentifier?: string | null;
}): boolean {
  const allowFrom = params.allowFrom.map((entry) => String(entry).trim());
  if (allowFrom.length === 0) {
    return true;
  }
  if (allowFrom.includes("*")) {
    return true;
  }

  const senderNormalized = normalizeIMessageHandle(params.sender);
  const chatId = params.chatId ?? undefined;
  const chatGuid = params.chatGuid?.trim();
  const chatIdentifier = params.chatIdentifier?.trim();

  for (const entry of allowFrom) {
    if (!entry) {
      continue;
    }
    const parsed = parseIMessageAllowTarget(entry);
    if (parsed.kind === "chat_id" && chatId !== undefined) {
      if (parsed.chatId === chatId) {
        return true;
      }
    } else if (parsed.kind === "chat_guid" && chatGuid) {
      if (parsed.chatGuid === chatGuid) {
        return true;
      }
    } else if (parsed.kind === "chat_identifier" && chatIdentifier) {
      if (parsed.chatIdentifier === chatIdentifier) {
        return true;
      }
    } else if (parsed.kind === "handle" && senderNormalized) {
      if (parsed.handle === senderNormalized) {
        return true;
      }
    }
  }
  return false;
}

export function formatIMessageChatTarget(chatId?: number | null): string {
  if (!chatId || !Number.isFinite(chatId)) {
    return "";
  }
  return `chat_id:${chatId}`;
}
