import {
  METRIC_COUNTER,
  METRICS_COUNTERS_KEY,
  METRICS_LATENCY_KEY,
  METRICS_LATENCY_MAX_SAMPLES,
  METRICS_QUOTE_START_PREFIX,
  METRICS_QUOTE_START_TTL_SECONDS,
} from "@/lib/constants/metrics";
import { getRedis } from "@/lib/redis";

export type MetricsCounters = Record<
  (typeof METRIC_COUNTER)[keyof typeof METRIC_COUNTER],
  number
>;

export type MetricsRates = {
  api_success_rate: number;
  rpa_success_rate: number;
  realtime_rate: number;
  cache_hit_rate: number;
};

export type MetricsSnapshot = MetricsRates & {
  counters: MetricsCounters;
  p95_latency_ms: number;
  latency_sample_count: number;
};

type DoneSource = "cache" | "rpa" | "stale";

function quoteStartKey(quoteId: string): string {
  return `${METRICS_QUOTE_START_PREFIX}${quoteId}`;
}

async function incrCounter(field: string, by = 1): Promise<void> {
  await getRedis().hincrby(METRICS_COUNTERS_KEY, field, by);
}

/** 安全埋点：不阻塞主流程，失败仅打日志 */
export function safeRecord(task: () => Promise<void>): void {
  void task().catch((error) => {
    console.error("[metrics] 采集失败:", error);
  });
}

/** 有效 POST 进入编排（校验通过后） */
export async function recordPostTotal(): Promise<void> {
  await incrCounter(METRIC_COUNTER.POST_TOTAL);
}

/** L1 / L2 缓存命中 */
export async function recordCacheHit(tier: "l1" | "l2"): Promise<void> {
  await incrCounter(
    tier === "l1"
      ? METRIC_COUNTER.CACHE_HIT_L1
      : METRIC_COUNTER.CACHE_HIT_L2,
  );
}

/** 触发 RPA 路径 */
export async function recordRpaTriggered(quoteId: string): Promise<void> {
  await incrCounter(METRIC_COUNTER.RPA_TRIGGERED);
  await markQuoteStarted(quoteId);
}

/** 记录询价开始时间（用于 P95） */
export async function markQuoteStarted(quoteId: string): Promise<void> {
  await getRedis().set(
    quoteStartKey(quoteId),
    String(Date.now()),
    "EX",
    METRICS_QUOTE_START_TTL_SECONDS,
  );
}

async function recordDoneLatency(quoteId: string): Promise<void> {
  const redis = getRedis();
  const startKey = quoteStartKey(quoteId);
  const startedAt = await redis.get(startKey);
  if (startedAt) {
    await redis.del(startKey);
    const latencyMs = Math.max(0, Date.now() - Number(startedAt));
    await redis.lpush(METRICS_LATENCY_KEY, String(latencyMs));
    await redis.ltrim(METRICS_LATENCY_KEY, 0, METRICS_LATENCY_MAX_SAMPLES - 1);
  }
}

/** 报价完成 done（含 cache / rpa / stale） */
export async function recordPostDone(params: {
  quoteId: string;
  sourceType: DoneSource;
  isRealtime: boolean;
}): Promise<void> {
  await incrCounter(METRIC_COUNTER.POST_DONE);
  await incrCounter(METRIC_COUNTER.DONE_TOTAL);

  if (params.isRealtime && params.sourceType !== "stale") {
    await incrCounter(METRIC_COUNTER.DONE_REALTIME);
  }

  if (params.sourceType === "rpa") {
    await incrCounter(METRIC_COUNTER.RPA_DONE);
  }

  await recordDoneLatency(params.quoteId);
}

export function computeRate(numerator: number, denominator: number): number {
  if (denominator <= 0) {
    return 0;
  }
  return Math.round((numerator / denominator) * 10_000) / 100;
}

export function computeP95(samples: number[]): number {
  if (samples.length === 0) {
    return 0;
  }
  const sorted = [...samples].sort((a, b) => a - b);
  const index = Math.ceil(sorted.length * 0.95) - 1;
  return sorted[Math.max(0, index)];
}

export function computeRates(counters: MetricsCounters): MetricsRates {
  const cacheHits =
    counters[METRIC_COUNTER.CACHE_HIT_L1] +
    counters[METRIC_COUNTER.CACHE_HIT_L2];

  return {
    api_success_rate: computeRate(
      counters[METRIC_COUNTER.POST_DONE],
      counters[METRIC_COUNTER.POST_TOTAL],
    ),
    rpa_success_rate: computeRate(
      counters[METRIC_COUNTER.RPA_DONE],
      counters[METRIC_COUNTER.RPA_TRIGGERED],
    ),
    realtime_rate: computeRate(
      counters[METRIC_COUNTER.DONE_REALTIME],
      counters[METRIC_COUNTER.DONE_TOTAL],
    ),
    cache_hit_rate: computeRate(
      cacheHits,
      counters[METRIC_COUNTER.POST_TOTAL],
    ),
  };
}

async function readCounters(): Promise<MetricsCounters> {
  const raw = await getRedis().hgetall(METRICS_COUNTERS_KEY);
  const counters = {} as MetricsCounters;

  for (const value of Object.values(METRIC_COUNTER)) {
    counters[value] = Number(raw[value] ?? 0);
  }

  return counters;
}

async function readLatencySamples(): Promise<number[]> {
  const raw = await getRedis().lrange(METRICS_LATENCY_KEY, 0, -1);
  return raw.map((item) => Number(item)).filter((item) => Number.isFinite(item));
}

/** 汇总 GD-4 四指标 + P95 */
export async function getMetricsSnapshot(): Promise<MetricsSnapshot> {
  const [counters, samples] = await Promise.all([
    readCounters(),
    readLatencySamples(),
  ]);

  return {
    ...computeRates(counters),
    counters,
    p95_latency_ms: computeP95(samples),
    latency_sample_count: samples.length,
  };
}

/** 测试用：清空指标 */
export async function resetMetrics(): Promise<void> {
  const redis = getRedis();
  const keys = await redis.keys(`${METRICS_QUOTE_START_PREFIX}*`);
  if (keys.length > 0) {
    await redis.del(...keys);
  }
  await redis.del(METRICS_COUNTERS_KEY, METRICS_LATENCY_KEY);
}
