/**
 * Approval system for managing DM, channel mention, and group invite approvals.
 *
 * When an unknown ship tries to interact with the bot, the owner receives
 * a notification and can approve or deny the request.
 */

import type { PendingApproval } from "../settings.js";

export type { PendingApproval };

export type ApprovalType = "dm" | "channel" | "group";

export type CreateApprovalParams = {
  type: ApprovalType;
  requestingShip: string;
  channelNest?: string;
  groupFlag?: string;
  messagePreview?: string;
  originalMessage?: {
    messageId: string;
    messageText: string;
    messageContent: unknown;
    timestamp: number;
    parentId?: string;
    isThreadReply?: boolean;
  };
};

/**
 * Generate a unique approval ID in the format: {type}-{timestamp}-{shortHash}
 */
export function generateApprovalId(type: ApprovalType): string {
  const timestamp = Date.now();
  const randomPart = Math.random().toString(36).substring(2, 6);
  return `${type}-${timestamp}-${randomPart}`;
}

/**
 * Create a pending approval object.
 */
export function createPendingApproval(params: CreateApprovalParams): PendingApproval {
  return {
    id: generateApprovalId(params.type),
    type: params.type,
    requestingShip: params.requestingShip,
    channelNest: params.channelNest,
    groupFlag: params.groupFlag,
    messagePreview: params.messagePreview,
    originalMessage: params.originalMessage,
    timestamp: Date.now(),
  };
}

/**
 * Truncate text to a maximum length with ellipsis.
 */
function truncate(text: string, maxLength: number): string {
  if (text.length <= maxLength) {
    return text;
  }
  return text.substring(0, maxLength - 3) + "...";
}

/**
 * Format a notification message for the owner about a pending approval.
 */
export function formatApprovalRequest(approval: PendingApproval): string {
  const preview = approval.messagePreview ? `\n"${truncate(approval.messagePreview, 100)}"` : "";

  switch (approval.type) {
    case "dm":
      return (
        `New DM request from ${approval.requestingShip}:${preview}\n\n` +
        `Reply "approve", "deny", or "block" (ID: ${approval.id})`
      );

    case "channel":
      return (
        `${approval.requestingShip} mentioned you in ${approval.channelNest}:${preview}\n\n` +
        `Reply "approve", "deny", or "block"\n` +
        `(ID: ${approval.id})`
      );

    case "group":
      return (
        `Group invite from ${approval.requestingShip} to join ${approval.groupFlag}\n\n` +
        `Reply "approve", "deny", or "block"\n` +
        `(ID: ${approval.id})`
      );
  }
}

export type ApprovalResponse = {
  action: "approve" | "deny" | "block";
  id?: string;
};

/**
 * Parse an owner's response to an approval request.
 * Supports formats:
 *   - "approve" / "deny" / "block" (applies to most recent pending)
 *   - "approve dm-1234567890-abc" / "deny dm-1234567890-abc" (specific ID)
 *   - "block" permanently blocks the ship via Tlon's native blocking
 */
export function parseApprovalResponse(text: string): ApprovalResponse | null {
  const trimmed = text.trim().toLowerCase();

  // Match "approve", "deny", or "block" optionally followed by an ID
  const match = trimmed.match(/^(approve|deny|block)(?:\s+(.+))?$/);
  if (!match) {
    return null;
  }

  const action = match[1] as "approve" | "deny" | "block";
  const id = match[2]?.trim();

  return { action, id };
}

/**
 * Check if a message text looks like an approval response.
 * Used to determine if we should intercept the message before normal processing.
 */
export function isApprovalResponse(text: string): boolean {
  const trimmed = text.trim().toLowerCase();
  return trimmed.startsWith("approve") || trimmed.startsWith("deny") || trimmed.startsWith("block");
}

/**
 * Find a pending approval by ID, or return the most recent if no ID specified.
 */
export function findPendingApproval(
  pendingApprovals: PendingApproval[],
  id?: string,
): PendingApproval | undefined {
  if (id) {
    return pendingApprovals.find((a) => a.id === id);
  }
  // Return most recent
  return pendingApprovals[pendingApprovals.length - 1];
}

/**
 * Check if there's already a pending approval for the same ship/channel/group combo.
 * Used to avoid sending duplicate notifications.
 */
export function hasDuplicatePending(
  pendingApprovals: PendingApproval[],
  type: ApprovalType,
  requestingShip: string,
  channelNest?: string,
  groupFlag?: string,
): boolean {
  return pendingApprovals.some((approval) => {
    if (approval.type !== type || approval.requestingShip !== requestingShip) {
      return false;
    }
    if (type === "channel" && approval.channelNest !== channelNest) {
      return false;
    }
    if (type === "group" && approval.groupFlag !== groupFlag) {
      return false;
    }
    return true;
  });
}

/**
 * Remove a pending approval from the list by ID.
 */
export function removePendingApproval(
  pendingApprovals: PendingApproval[],
  id: string,
): PendingApproval[] {
  return pendingApprovals.filter((a) => a.id !== id);
}

/**
 * Format a confirmation message after an approval action.
 */
export function formatApprovalConfirmation(
  approval: PendingApproval,
  action: "approve" | "deny" | "block",
): string {
  if (action === "block") {
    return `Blocked ${approval.requestingShip}. They will no longer be able to contact the bot.`;
  }

  const actionText = action === "approve" ? "Approved" : "Denied";

  switch (approval.type) {
    case "dm":
      if (action === "approve") {
        return `${actionText} DM access for ${approval.requestingShip}. They can now message the bot.`;
      }
      return `${actionText} DM request from ${approval.requestingShip}.`;

    case "channel":
      if (action === "approve") {
        return `${actionText} ${approval.requestingShip} for ${approval.channelNest}. They can now interact in this channel.`;
      }
      return `${actionText} ${approval.requestingShip} for ${approval.channelNest}.`;

    case "group":
      if (action === "approve") {
        return `${actionText} group invite from ${approval.requestingShip} to ${approval.groupFlag}. Joining group...`;
      }
      return `${actionText} group invite from ${approval.requestingShip} to ${approval.groupFlag}.`;
  }
}

// ============================================================================
// Admin Commands
// ============================================================================

export type AdminCommand =
  | { type: "unblock"; ship: string }
  | { type: "blocked" }
  | { type: "pending" };

/**
 * Parse an admin command from owner message.
 * Supports:
 *   - "unblock ~ship" - unblock a specific ship
 *   - "blocked" - list all blocked ships
 *   - "pending" - list all pending approvals
 */
export function parseAdminCommand(text: string): AdminCommand | null {
  const trimmed = text.trim().toLowerCase();

  // "blocked" - list blocked ships
  if (trimmed === "blocked") {
    return { type: "blocked" };
  }

  // "pending" - list pending approvals
  if (trimmed === "pending") {
    return { type: "pending" };
  }

  // "unblock ~ship" - unblock a specific ship
  const unblockMatch = trimmed.match(/^unblock\s+(~[\w-]+)$/);
  if (unblockMatch) {
    return { type: "unblock", ship: unblockMatch[1] };
  }

  return null;
}

/**
 * Check if a message text looks like an admin command.
 */
export function isAdminCommand(text: string): boolean {
  return parseAdminCommand(text) !== null;
}

/**
 * Format the list of blocked ships for display to owner.
 */
export function formatBlockedList(ships: string[]): string {
  if (ships.length === 0) {
    return "No ships are currently blocked.";
  }
  return `Blocked ships (${ships.length}):\n${ships.map((s) => `• ${s}`).join("\n")}`;
}

/**
 * Format the list of pending approvals for display to owner.
 */
export function formatPendingList(approvals: PendingApproval[]): string {
  if (approvals.length === 0) {
    return "No pending approval requests.";
  }
  return `Pending approvals (${approvals.length}):\n${approvals
    .map((a) => `• ${a.id}: ${a.type} from ${a.requestingShip}`)
    .join("\n")}`;
}
