import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { Logger } from 'nestjs-pino';

type GrafanaQueryPayload = Record<string, unknown>;

@Injectable()
export class GrafanaQueryService {
  constructor(private readonly logger: Logger) {}

  async query(body: GrafanaQueryPayload, orgIdHeader?: string): Promise<unknown> {
    if (!body || typeof body !== 'object') {
      throw new HttpException('Invalid request body', HttpStatus.BAD_REQUEST);
    }

    const baseUrl = (process.env.GRAFANA_BASE_URL ?? '').trim().replace(/\/+$/, '');
    const user = process.env.GRAFANA_BASIC_USER;
    const pass = process.env.GRAFANA_BASIC_PASSWORD;
    const orgId = orgIdHeader || process.env.GRAFANA_ORG_ID || '1';

    if (!baseUrl) {
      throw new HttpException('GRAFANA_BASE_URL not configured', HttpStatus.SERVICE_UNAVAILABLE);
    }
    if (!user || !pass) {
      throw new HttpException('Grafana basic auth not configured', HttpStatus.SERVICE_UNAVAILABLE);
    }

    let targetUrl: URL;
    try {
      targetUrl = new URL('/api/ds/query', baseUrl);
    } catch {
      throw new HttpException('Invalid GRAFANA_BASE_URL', HttpStatus.SERVICE_UNAVAILABLE);
    }

    const auth = Buffer.from(`${user}:${pass}`).toString('base64');

    const response = await fetch(targetUrl.toString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Basic ${auth}`,
        'X-Grafana-Org-Id': orgId,
      },
      body: JSON.stringify(body),
    });

    const text = await response.text();
    let payload: unknown = text;
    try {
      payload = text ? JSON.parse(text) : null;
    } catch {
      payload = text;
    }

    if (!response.ok) {
      this.logger.error(
        {
          status: response.status,
          statusText: response.statusText,
          body: text.slice(0, 1000),
        },
        'Grafana proxy query failed'
      );
      throw new HttpException('Upstream Grafana query failed', response.status as HttpStatus);
    }

    return payload;
  }
}
