import { baseUrl } from "@/api/baseUrl";
import { generateFixedHash, isValidId } from "./stringUtil";
import type { LiveStreamMetadata } from "@/types/live";

/**
 * Processes a user-entered camera name and returns both the final camera name
 * and friendly name for Frigate configuration.
 *
 * @param userInput - The name entered by the user (could be display name)
 * @returns Object with finalCameraName and friendlyName
 */
export function processCameraName(userInput: string): {
  finalCameraName: string;
  friendlyName?: string;
} {
  const normalizedInput = userInput.replace(/\s+/g, "_").toLowerCase();

  if (isValidId(normalizedInput)) {
    return {
      finalCameraName: normalizedInput,
      friendlyName: userInput.includes(" ") ? userInput : undefined,
    };
  }

  return {
    finalCameraName: generateFixedHash(userInput, "cam"),
    friendlyName: userInput,
  };
}

/**
 * Detect Reolink camera capabilities and recommend optimal protocol
 *
 * Calls the Frigate backend API which queries the Reolink camera to determine
 * its resolution and recommends either http-flv (for 5MP and below) or rtsp
 * (for higher resolutions).
 *
 * @param host - Camera IP address or hostname
 * @param username - Camera username
 * @param password - Camera password
 * @returns The recommended protocol key ("http-flv" or "rtsp"), or null if detection failed
 */
export async function detectReolinkCamera(
  host: string,
  username: string,
  password: string,
): Promise<"http-flv" | "rtsp" | null> {
  try {
    const params = new URLSearchParams({
      host,
      username,
      password,
    });

    const response = await fetch(
      `${baseUrl}api/reolink/detect?${params.toString()}`,
      {
        method: "GET",
      },
    );

    if (!response.ok) {
      return null;
    }

    const data = await response.json();

    if (data.success && data.protocol) {
      return data.protocol;
    }

    return null;
  } catch (error) {
    return null;
  }
}

/**
 * Mask credentials in RTSP URIs for display
 */
export function maskUri(uri: string): string {
  try {
    // Handle RTSP URLs with user:pass@host format
    // Use greedy match for password to handle passwords with @
    const rtspMatch = uri.match(/rtsp:\/\/([^:]+):(.+)@(.+)/);
    if (rtspMatch) {
      return `rtsp://${rtspMatch[1]}:${"*".repeat(4)}@${rtspMatch[3]}`;
    }

    // Handle HTTP/HTTPS URLs with password query parameter
    const urlObj = new URL(uri);
    if (urlObj.searchParams.has("password")) {
      urlObj.searchParams.set("password", "*".repeat(4));
      return urlObj.toString();
    }
  } catch (e) {
    // ignore
  }
  return uri;
}

/**
 * Represents the audio features supported by a camera stream
 */
export type CameraAudioFeatures = {
  twoWayAudio: boolean;
  audioOutput: boolean;
};

/**
 * Detects camera audio features from go2rtc stream metadata.
 * Checks for two-way audio (backchannel) and audio output capabilities.
 *
 * @param metadata - The LiveStreamMetadata from go2rtc stream
 * @param requireSecureContext - If true, two-way audio requires secure context (default: true)
 * @returns CameraAudioFeatures object with detected capabilities
 */
/**
 * Calculates optimal detect dimensions from stream resolution.
 *
 * Scales dimensions to an efficient size for object detection while
 * preserving the stream's aspect ratio. Does not upscale.
 *
 * @param streamWidth - Native stream width in pixels
 * @param streamHeight - Native stream height in pixels
 * @returns Detect dimensions with even values, or null if inputs are invalid
 */

// Target size for the smaller dimension (width or height) for detect streams
export const DETECT_TARGET_PX = 720;

export function calculateDetectDimensions(
  streamWidth: number,
  streamHeight: number,
): { width: number; height: number } | null {
  if (
    !Number.isFinite(streamWidth) ||
    !Number.isFinite(streamHeight) ||
    streamWidth <= 0 ||
    streamHeight <= 0
  ) {
    return null;
  }

  const smallerDim = Math.min(streamWidth, streamHeight);
  const target = Math.min(DETECT_TARGET_PX, smallerDim);
  const scale = target / smallerDim;

  let width = Math.round(streamWidth * scale);
  let height = Math.round(streamHeight * scale);

  // Round down to even numbers (required for video processing)
  width = width - (width % 2);
  height = height - (height % 2);

  if (width < 2 || height < 2) {
    return null;
  }

  return { width, height };
}

export function detectCameraAudioFeatures(
  metadata: LiveStreamMetadata | null | undefined,
  requireSecureContext: boolean = true,
): CameraAudioFeatures {
  if (!metadata) {
    return {
      twoWayAudio: false,
      audioOutput: false,
    };
  }

  const twoWayAudio =
    (!requireSecureContext || window.isSecureContext) &&
    metadata.producers.find(
      (prod) =>
        prod.medias &&
        prod.medias.find((media) => media.includes("audio, sendonly")) !=
          undefined,
    ) != undefined;

  const audioOutput =
    metadata.producers.find(
      (prod) =>
        prod.medias &&
        prod.medias.find((media) => media.includes("audio, recvonly")) !=
          undefined,
    ) != undefined;

  return {
    twoWayAudio: !!twoWayAudio,
    audioOutput: !!audioOutput,
  };
}

const REPLAY_CAMERA_PREFIX = "_replay_";

/**
 * Check if a camera name is a debug replay camera.
 *
 * @param name - The camera name to check
 * @returns true if the camera is a replay camera
 */
export function isReplayCamera(name: string): boolean {
  return name.startsWith(REPLAY_CAMERA_PREFIX);
}
