import type { McpdClient } from '../http/mcpd-client.js';
import type { ProviderRegistry } from '../providers/registry.js';

export interface McplocalHealth {
  status: 'healthy' | 'degraded';
  uptime: number;
  llmProvider: string | null;
}

export interface McpdHealth {
  status: 'connected' | 'disconnected';
  url: string;
}

export interface InstanceHealth {
  name: string;
  status: string;
}

export interface TieredHealthStatus {
  mcplocal: McplocalHealth;
  mcpd: McpdHealth;
  instances: InstanceHealth[];
}

export interface TieredHealthMonitorDeps {
  mcpdClient: McpdClient | null;
  providerRegistry: ProviderRegistry;
  mcpdUrl: string;
}

/**
 * Monitors health across all tiers: mcplocal itself, the mcpd daemon, and MCP server instances.
 * Aggregates status from multiple sources into a single TieredHealthStatus.
 */
export class TieredHealthMonitor {
  private readonly mcpdClient: McpdClient | null;
  private readonly providerRegistry: ProviderRegistry;
  private readonly mcpdUrl: string;
  private readonly startTime: number;

  constructor(deps: TieredHealthMonitorDeps) {
    this.mcpdClient = deps.mcpdClient;
    this.providerRegistry = deps.providerRegistry;
    this.mcpdUrl = deps.mcpdUrl;
    this.startTime = Date.now();
  }

  async checkHealth(): Promise<TieredHealthStatus> {
    const [mcpdHealth, instances] = await Promise.all([
      this.checkMcpd(),
      this.fetchInstances(),
    ]);

    const mcplocalHealth = this.checkMcplocal();

    return {
      mcplocal: mcplocalHealth,
      mcpd: mcpdHealth,
      instances,
    };
  }

  private checkMcplocal(): McplocalHealth {
    const activeProvider = this.providerRegistry.getActive();
    return {
      status: 'healthy',
      uptime: (Date.now() - this.startTime) / 1000,
      llmProvider: activeProvider?.name ?? null,
    };
  }

  private async checkMcpd(): Promise<McpdHealth> {
    if (this.mcpdClient === null) {
      return { status: 'disconnected', url: this.mcpdUrl };
    }

    try {
      await this.mcpdClient.get<unknown>('/health');
      return { status: 'connected', url: this.mcpdUrl };
    } catch {
      return { status: 'disconnected', url: this.mcpdUrl };
    }
  }

  private async fetchInstances(): Promise<InstanceHealth[]> {
    if (this.mcpdClient === null) {
      return [];
    }

    try {
      const response = await this.mcpdClient.get<{ instances: InstanceHealth[] }>('/instances');
      return response.instances;
    } catch {
      return [];
    }
  }
}
