import { Client } from "@elastic/elasticsearch";
import { env } from "./env.js";
import { logger } from "../shared/observability/logger.js";

export const esClient: Client | null = env.ES_URL
  ? new Client({ node: env.ES_URL })
  : null;

export async function checkEsConnection(): Promise<void> {
  if (!esClient) {
    logger.info("Elasticsearch disabled (ES_URL not set)");
    return;
  }
  try {
    await esClient.ping();
    logger.info("Elasticsearch connected");
  } catch (err) {
    logger.error({ err }, "Elasticsearch connection failed");
  }
}

export async function closeEs(): Promise<void> {
  if (esClient) {
    await esClient.close();
  }
}

export interface IndexParams {
  index: string;
  id: string;
  document: Record<string, unknown>;
}

export interface SearchHit {
  _id: string;
  _source: Record<string, unknown>;
}

export interface SearchResult {
  hits: SearchHit[];
}

export async function safeIndex(params: IndexParams): Promise<boolean> {
  if (!esClient) return false;
  try {
    await esClient.index(params);
    return true;
  } catch (err) {
    logger.error(
      { err, index: params.index, id: params.id },
      "Elasticsearch index failed",
    );
    return false;
  }
}

export async function safeSearch(
  index: string,
  query: Record<string, unknown>,
): Promise<SearchResult> {
  if (!esClient) return { hits: [] };
  try {
    const result = await esClient.search({ index, query });
    const hits: SearchHit[] = [];
    for (const raw of result.hits.hits) {
      const source = raw._source;
      if (
        raw._id &&
        source &&
        typeof source === "object" &&
        !Array.isArray(source)
      ) {
        // source 已收窄为 object，但 object 无索引签名，需断言为 Record<string, unknown>
        hits.push({
          _id: raw._id,
          _source: source as Record<string, unknown>,
        });
      }
    }
    return { hits };
  } catch (err) {
    logger.error({ err, index }, "Elasticsearch search failed");
    return { hits: [] };
  }
}
