import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  IAiAgentClient,
  AgentChatRequest,
  AgentChatResponse,
  AgentCreditScoreRequest,
  AgentCreditScoreResponse,
  AgentPricingRequest,
  AgentPricingResponse,
  AgentAnomalyRequest,
  AgentAnomalyResponse,
  AgentStatsResponse,
  AgentTopQuestion,
  AgentSessionsResponse,
  AgentSatisfactionMetrics,
} from '../../domain/ports/ai-agent.client.interface';

/**
 * Concrete implementation of IAiAgentClient.
 *
 * Encapsulates ALL HTTP communication with the external AI agent cluster.
 * This is the single place where fetch() calls, timeouts, headers, and
 * API key handling live. No other layer should make direct HTTP calls.
 */
@Injectable()
export class AiAgentClient implements IAiAgentClient {
  private readonly logger = new Logger(AiAgentClient.name);
  private readonly agentUrl: string;
  private readonly apiKey: string;
  private readonly timeout: number;

  constructor(private readonly config: ConfigService) {
    this.agentUrl = this.config.get<string>('AI_AGENT_CLUSTER_URL', 'http://localhost:8000');
    this.apiKey = this.config.get<string>('AI_AGENT_API_KEY', '');
    this.timeout = this.config.get<number>('AI_AGENT_TIMEOUT', 30000);
  }

  // ── Core AI capabilities ──────────────────────────────────────────────────

  async chat(req: AgentChatRequest): Promise<AgentChatResponse> {
    const raw = await this.post('/api/v1/chat', {
      user_id: req.userId,
      message: req.message,
      session_id: req.sessionId,
      context: req.context,
    });
    return {
      reply: raw.reply || raw.message || '',
      sessionId: raw.session_id || req.sessionId || `session-${Date.now()}`,
      suggestions: raw.suggestions || [],
    };
  }

  async creditScore(req: AgentCreditScoreRequest): Promise<AgentCreditScoreResponse> {
    return this.post('/api/v1/credit/score', req);
  }

  async pricing(req: AgentPricingRequest): Promise<AgentPricingResponse> {
    return this.post('/api/v1/pricing/suggest', req);
  }

  async anomalyDetect(req: AgentAnomalyRequest): Promise<AgentAnomalyResponse> {
    return this.post('/api/v1/anomaly/check', req);
  }

  // ── Admin endpoints ───────────────────────────────────────────────────────

  async getStats(): Promise<AgentStatsResponse> {
    return this.get('/api/v1/admin/stats');
  }

  async getTopQuestions(limit: number): Promise<AgentTopQuestion[]> {
    return this.get(`/api/v1/admin/top-questions?limit=${limit}`);
  }

  async getSessions(page: number, limit: number): Promise<AgentSessionsResponse> {
    return this.get(`/api/v1/admin/sessions?page=${page}&limit=${limit}`);
  }

  async getSatisfactionMetrics(): Promise<AgentSatisfactionMetrics> {
    return this.get('/api/v1/admin/satisfaction');
  }

  async configureModule(moduleId: string, config: Record<string, any>): Promise<void> {
    await this.post(`/api/v1/admin/modules/${moduleId}/config`, config);
  }

  async healthCheck(): Promise<boolean> {
    try {
      const res = await this.fetchWithTimeout(`${this.agentUrl}/health`, {
        method: 'GET',
        headers: this.buildHeaders(),
      });
      return res.ok;
    } catch {
      return false;
    }
  }

  // ── Private HTTP helpers ──────────────────────────────────────────────────

  private async post(path: string, body: any): Promise<any> {
    const res = await this.fetchWithTimeout(`${this.agentUrl}${path}`, {
      method: 'POST',
      headers: this.buildHeaders(),
      body: JSON.stringify(body),
    });
    if (!res.ok) {
      throw new Error(`AI Agent returned HTTP ${res.status} for POST ${path}`);
    }
    return res.json();
  }

  private async get(path: string): Promise<any> {
    const res = await this.fetchWithTimeout(`${this.agentUrl}${path}`, {
      method: 'GET',
      headers: this.buildHeaders(),
    });
    if (!res.ok) {
      throw new Error(`AI Agent returned HTTP ${res.status} for GET ${path}`);
    }
    return res.json();
  }

  private async fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);
    try {
      return await fetch(url, { ...init, signal: controller.signal });
    } finally {
      clearTimeout(timeoutId);
    }
  }

  private buildHeaders(): Record<string, string> {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    };
    if (this.apiKey) {
      headers['Authorization'] = `Bearer ${this.apiKey}`;
    }
    return headers;
  }
}
