/**
 * 分布式追踪上下文服务
 * 
 * 提供 traceId/spanId/parentSpanId 的生成和管理
 * 支持跨服务调用追踪
 * 
 * 设计兼容 OpenTelemetry 规范
 */

import { Injectable, Scope } from '@nestjs/common';
import { Request } from 'express';

// 追踪上下文接口
export interface TraceContext {
  traceId: string;       // 全局追踪 ID（跨服务）
  spanId: string;        // 当前操作 ID
  parentSpanId?: string; // 父操作 ID（调用链）
  
  region: string;        // 区域: CN | US | UAE
  service: string;       // 服务: IAM | Form | Approval | Inventory
  instance: string;      // 实例 ID
  
  workflowId?: string;   // Temporal Workflow ID
  activityId?: string;   // Temporal Activity ID
}

// HTTP Header 名称
export const TRACE_HEADERS = {
  TRACE_ID: 'X-Trace-Id',
  SPAN_ID: 'X-Span-Id',
  PARENT_SPAN_ID: 'X-Parent-Span-Id',
  REQUEST_ID: 'X-Request-Id',
} as const;

@Injectable({ scope: Scope.DEFAULT })
export class TraceContextService {
  private readonly region: string;
  private readonly service: string;
  private readonly instance: string;

  constructor() {
    this.region = process.env.LOG_REGION || process.env.REGION || 'CN';
    this.service = process.env.LOG_SERVICE || 'Backend';
    this.instance = process.env.LOG_INSTANCE || process.env.HOSTNAME || `instance-${this.generateRandom(4)}`;
  }

  /**
   * 生成新的追踪上下文
   * 用于入口请求（没有上游追踪信息）
   */
  createContext(): TraceContext {
    const traceId = this.generateTraceId();
    const spanId = this.generateSpanId();

    return {
      traceId,
      spanId,
      region: this.region,
      service: this.service,
      instance: this.instance,
    };
  }

  /**
   * 从 HTTP 请求中提取或创建追踪上下文
   * 如果请求中有上游追踪信息，则继承；否则创建新的
   */
  extractOrCreate(request: Request): TraceContext {
    const headers = request.headers;

    // 尝试从 Header 中提取上游追踪信息
    const upstreamTraceId = headers[TRACE_HEADERS.TRACE_ID.toLowerCase()] as string;
    const upstreamSpanId = headers[TRACE_HEADERS.SPAN_ID.toLowerCase()] as string;

    // 如果有上游 traceId，继承它
    const traceId = upstreamTraceId || this.generateTraceId();
    
    // 生成新的 spanId（当前操作）
    const spanId = this.generateSpanId();
    
    // 上游的 spanId 变成当前的 parentSpanId
    const parentSpanId = upstreamSpanId || undefined;

    return {
      traceId,
      spanId,
      parentSpanId,
      region: this.region,
      service: this.service,
      instance: this.instance,
    };
  }

  /**
   * 为下游服务调用创建子追踪上下文
   * 用于调用其他服务时传递追踪信息
   */
  createChildContext(parentContext: TraceContext): TraceContext {
    return {
      traceId: parentContext.traceId,
      spanId: this.generateSpanId(),
      parentSpanId: parentContext.spanId,
      region: this.region,
      service: this.service,
      instance: this.instance,
    };
  }

  /**
   * 生成传递给下游服务的 HTTP Headers
   */
  toHeaders(context: TraceContext): Record<string, string> {
    const headers: Record<string, string> = {
      [TRACE_HEADERS.TRACE_ID]: context.traceId,
      [TRACE_HEADERS.SPAN_ID]: context.spanId,
    };

    if (context.parentSpanId) {
      headers[TRACE_HEADERS.PARENT_SPAN_ID] = context.parentSpanId;
    }

    return headers;
  }

  /**
   * 生成 traceId
   * 格式: {region}-{timestamp}-{random8}
   * 示例: CN-1733580000000-a1b2c3d4
   */
  generateTraceId(): string {
    const timestamp = Date.now();
    const random = this.generateRandom(8);
    return `${this.region}-${timestamp}-${random}`;
  }

  /**
   * 生成 spanId
   * 格式: {service}-{timestamp}-{random6}
   * 示例: FORM-1733580000123-x1y2z3
   */
  generateSpanId(): string {
    const timestamp = Date.now();
    const random = this.generateRandom(6);
    return `${this.service}-${timestamp}-${random}`;
  }

  /**
   * 生成 requestId
   * 格式: {timestamp}-{random7}
   * 示例: 1733580000123-abc1234
   */
  generateRequestId(): string {
    const timestamp = Date.now();
    const random = this.generateRandom(7);
    return `${timestamp}-${random}`;
  }

  /**
   * 生成随机字符串
   */
  private generateRandom(length: number): string {
    return Math.random().toString(36).substring(2, 2 + length);
  }

  /**
   * 获取当前区域
   */
  getRegion(): string {
    return this.region;
  }

  /**
   * 获取当前服务名
   */
  getService(): string {
    return this.service;
  }

  /**
   * 获取当前实例 ID
   */
  getInstance(): string {
    return this.instance;
  }
}

