import { CloudWatchClient, PutMetricDataCommand, StandardUnit } from '@aws-sdk/client-cloudwatch';
import { getMonitoringConfig } from './config';

let client: CloudWatchClient | null = null;

function getClient(): CloudWatchClient | null {
  if (client) return client;

  const config = getMonitoringConfig();
  const region = process.env.AWS_REGION || 'us-east-1';

  try {
    client = new CloudWatchClient({ region });
    return client;
  } catch {
    console.warn('[CloudWatch] Metrics client initialization skipped');
    return null;
  }
}

export interface MetricDataPoint {
  MetricName: string;
  Dimensions?: { Name: string; Value: string }[];
  Value: number;
  Unit?: string;
  Timestamp?: Date;
}

const NAMESPACE = 'ShieldAI';

export async function emitMetric(
  serviceName: string,
  metricName: string,
  value: number,
  unit: StandardUnit = 'Count',
  dimensions?: Record<string, string>
) {
  const cw = getClient();
  if (!cw) return;

  const dims: { Name: string; Value: string }[] = [
    { Name: 'service', Value: serviceName },
    ...(dimensions ? Object.entries(dimensions).map(([n, v]) => ({ Name: n, Value: v })) : []),
  ];

  const command = new PutMetricDataCommand({
    Namespace: NAMESPACE,
    MetricData: [
      {
        MetricName: metricName,
        Dimensions: dims,
        Value: value,
        Unit: unit,
      },
    ],
  });

  try {
    await cw.send(command);
  } catch (err) {
    console.warn('[CloudWatch] Metric emit failed:', (err as Error).message);
  }
}

export async function emitBatchMetrics(metrics: {
  serviceName: string;
  data: { metricName: string; value: number; unit: StandardUnit; dimensions?: Record<string, string> }[];
}) {
  const cw = getClient();
  if (!cw) return;

  const metricData = metrics.data.map((m) => ({
    MetricName: m.metricName,
    Dimensions: [
      { Name: 'service', Value: metrics.serviceName },
      ...(m.dimensions ? Object.entries(m.dimensions).map(([n, v]) => ({ Name: n, Value: v })) : []),
    ],
    Value: m.value,
    Unit: m.unit,
  }));

  const command = new PutMetricDataCommand({
    Namespace: NAMESPACE,
    MetricData: metricData,
  });

  try {
    await cw.send(command);
  } catch (err) {
    console.warn('[CloudWatch] Batch metric emit failed:', (err as Error).message);
  }
}

export async function emitLatency(
  serviceName: string,
  latencyMs: number,
  percentile: 'p50' | 'p95' | 'p99'
) {
  await emitMetric(
    serviceName,
    'api_latency',
    latencyMs,
    'Milliseconds' as StandardUnit,
    { percentile }
  );
}

export async function emitRequestCount(serviceName: string, statusCode: number) {
  await emitMetric(
    serviceName,
    'api_requests',
    1,
    'Count' as StandardUnit,
    { status_class: String(Math.floor(statusCode / 100)) + 'xx' }
  );
}

export async function emitError(serviceName: string, errorType: string) {
  await emitMetric(
    serviceName,
    'api_errors',
    1,
    'Count' as StandardUnit,
    { error_type: errorType }
  );
}
