import { getGraylogCredentials, getTuleapCredentials } from "./api";
import type { ProcessedTicket } from "./types";

export interface TicketResourceConfig {
  tuleapUrl: string | null;
  graylogBaseUrl: string | null;
  graylogLookbackMinutes: number;
}

export interface TicketResourceLink {
  href: string;
  label: string;
}

export const DEFAULT_TICKET_RESOURCE_CONFIG: TicketResourceConfig = {
  tuleapUrl: null,
  graylogBaseUrl: null,
  graylogLookbackMinutes: 30,
};

function normalizeBaseUrl(value: string): string {
  return value.trim().replace(/\/+$/, "");
}

function isAbsoluteUrl(value: string | null | undefined): boolean {
  if (!value) return false;
  return /^https?:\/\//i.test(value.trim());
}

function escapeGraylogQueryValue(value: string): string {
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}

function parseGraylogSubjectPayload(
  artifactData: string
): { source?: string; normalizedMessage?: string } {
  try {
    const parsed = JSON.parse(artifactData) as Record<string, unknown>;
    const source = typeof parsed.source === "string" ? parsed.source.trim() : "";
    const normalizedMessage =
      typeof parsed.normalized_message === "string" ? parsed.normalized_message.trim() : "";
    return {
      source: source || undefined,
      normalizedMessage: normalizedMessage || undefined,
    };
  } catch {
    return {};
  }
}

function buildGraylogPermalink(
  baseUrl: string,
  source: string | undefined,
  normalizedMessage: string | undefined,
  lookbackMinutes: number
): string {
  const terms: string[] = [];
  if (source) {
    terms.push(`source:"${escapeGraylogQueryValue(source)}"`);
  }
  if (normalizedMessage) {
    terms.push(`message:"${escapeGraylogQueryValue(normalizedMessage)}"`);
  }

  const query = terms.length > 0 ? terms.join(" AND ") : "*";
  const relativeSeconds = Math.max(60, Math.max(1, lookbackMinutes) * 60);
  const params = new URLSearchParams({
    q: query,
    rangetype: "relative",
    relative: String(relativeSeconds),
  });

  return `${normalizeBaseUrl(baseUrl)}/search?${params.toString()}`;
}

function buildTuleapLink(
  ticket: ProcessedTicket,
  config: TicketResourceConfig
): TicketResourceLink | null {
  if (isAbsoluteUrl(ticket.source_ref)) {
    return { href: ticket.source_ref!.trim(), label: "Ouvrir dans Tuleap" };
  }

  if (!config.tuleapUrl) {
    return null;
  }

  const artifactId =
    ticket.artifact_id > 0
      ? ticket.artifact_id
      : Number.parseInt(ticket.source_ref ?? "", 10);

  if (!Number.isFinite(artifactId) || artifactId <= 0) {
    return null;
  }

  return {
    href: `${normalizeBaseUrl(config.tuleapUrl)}/plugins/tracker/?aid=${artifactId}`,
    label: "Ouvrir dans Tuleap",
  };
}

function buildGraylogLink(
  ticket: ProcessedTicket,
  config: TicketResourceConfig
): TicketResourceLink | null {
  if (isAbsoluteUrl(ticket.source_ref)) {
    return { href: ticket.source_ref!.trim(), label: "Ouvrir dans Graylog" };
  }

  if (!config.graylogBaseUrl) {
    return null;
  }

  const payload = parseGraylogSubjectPayload(ticket.artifact_data);
  const fallbackMessage = ticket.source_ref?.trim() || undefined;

  return {
    href: buildGraylogPermalink(
      config.graylogBaseUrl,
      payload.source,
      payload.normalizedMessage ?? fallbackMessage,
      config.graylogLookbackMinutes
    ),
    label: "Ouvrir dans Graylog",
  };
}

export function buildTicketResourceLink(
  ticket: ProcessedTicket,
  config: TicketResourceConfig
): TicketResourceLink | null {
  if (ticket.source === "tuleap") {
    return buildTuleapLink(ticket, config);
  }
  if (ticket.source === "graylog") {
    return buildGraylogLink(ticket, config);
  }
  return null;
}

export async function fetchTicketResourceConfig(
  projectId: string
): Promise<TicketResourceConfig> {
  const [tuleapCredentials, graylogCredentials] = await Promise.all([
    getTuleapCredentials(projectId),
    getGraylogCredentials(projectId),
  ]);

  return {
    tuleapUrl: tuleapCredentials?.tuleap_url ?? null,
    graylogBaseUrl: graylogCredentials?.base_url ?? null,
    graylogLookbackMinutes: graylogCredentials?.lookback_minutes ?? 30,
  };
}
