import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { ZABBIX_STATUS_KEYS, formatAgeSeconds, formatDuration, formatKstIso } from './zabbix-utils';
import type { ZabbixItem } from './zabbix-types';
import { ZabbixClientService } from './zabbix-client.service';

@Injectable()
export class ZabbixStatusService {
  constructor(private readonly zabbixClient: ZabbixClientService) {}

  async getSummary(
    orgIdHeader?: string
  ): Promise<{ rows: Array<Record<string, string | number | null>> }> {
    const hosts = await this.zabbixClient.fetchHosts(
      {
        output: ['hostid', 'host', 'name'],
        sortfield: 'name',
      },
      orgIdHeader
    );

    const hostIds = hosts.map((host) => host.hostid).filter(Boolean);
    if (hostIds.length === 0) {
      return { rows: [] };
    }

    const items = await this.zabbixClient.fetchItems(
      {
        output: ['itemid', 'hostid', 'key_', 'lastvalue', 'lastclock'],
        hostids: hostIds,
        filter: { key_: [...ZABBIX_STATUS_KEYS] },
      },
      orgIdHeader
    );

    const itemByHost: Record<string, Partial<Record<(typeof ZABBIX_STATUS_KEYS)[number], ZabbixItem>>> =
      {};
    for (const item of items) {
      if (!itemByHost[item.hostid]) {
        itemByHost[item.hostid] = {};
      }
      if (item.key_ === 'agent.ping' || item.key_ === 'system.uptime') {
        itemByHost[item.hostid][item.key_ as (typeof ZABBIX_STATUS_KEYS)[number]] = item;
      }
    }

    const rows = hosts
      .map((host) => {
        const hostName = host.host || host.name || '';
        const statusItems = itemByHost[host.hostid] || {};
        const agent = statusItems['agent.ping'];
        const uptime = statusItems['system.uptime'];

        const agentValue = agent?.lastvalue ?? null;
        const agentStatus =
          agentValue === '1' ? 'UP' : agentValue === '0' ? 'DOWN' : 'UNKNOWN';
        const agentLastSeen = formatAgeSeconds(agent?.lastclock);
        const statusSummary =
          agentStatus && agentLastSeen ? `${agentStatus} · ${agentLastSeen}` : agentStatus;

        return {
          host: hostName,
          agent_status: agentStatus,
          agent_lastclock: agent?.lastclock ?? null,
          agent_lastclock_kst: formatKstIso(agent?.lastclock),
          agent_last_seen_human: agentLastSeen,
          status_summary: statusSummary,
          uptime_sec: uptime?.lastvalue ?? null,
          uptime_human: formatDuration(uptime?.lastvalue),
          uptime_lastclock: uptime?.lastclock ?? null,
          uptime_lastclock_kst: formatKstIso(uptime?.lastclock),
        };
      })
      .sort((a, b) => a.host.localeCompare(b.host));

    return { rows };
  }

  async getHostStatus(
    orgIdHeader?: string,
    hostName?: string
  ): Promise<{
    host: string;
    status_summary: string | null;
    uptime_human: string | null;
    rows: Array<{ label: string; value: string | null }>;
  }> {
    if (!hostName || !hostName.trim()) {
      throw new HttpException('host query param is required', HttpStatus.BAD_REQUEST);
    }

    const host = await this.zabbixClient.requireHostByName(hostName, orgIdHeader);

    const items = await this.zabbixClient.fetchItems(
      {
        output: ['itemid', 'hostid', 'key_', 'lastvalue', 'lastclock'],
        hostids: [host.hostid],
        filter: { key_: [...ZABBIX_STATUS_KEYS] },
      },
      orgIdHeader
    );

    const itemByKey: Partial<Record<(typeof ZABBIX_STATUS_KEYS)[number], ZabbixItem>> = {};
    for (const item of items) {
      if (item.key_ === 'agent.ping' || item.key_ === 'system.uptime') {
        itemByKey[item.key_ as (typeof ZABBIX_STATUS_KEYS)[number]] = item;
      }
    }

    const agent = itemByKey['agent.ping'];
    const uptime = itemByKey['system.uptime'];

    const agentValue = agent?.lastvalue ?? null;
    const agentStatus =
      agentValue === '1' ? 'UP' : agentValue === '0' ? 'DOWN' : 'UNKNOWN';
    const agentLastSeen = formatAgeSeconds(agent?.lastclock);
    const statusSummary =
      agentStatus && agentLastSeen ? `${agentStatus} · ${agentLastSeen}` : agentStatus;

    const uptimeHuman = formatDuration(uptime?.lastvalue);

    return {
      host: host.host || host.name || hostName,
      status_summary: statusSummary,
      uptime_human: uptimeHuman,
      rows: [
        { label: 'Status', value: statusSummary },
        { label: 'Uptime', value: uptimeHuman },
      ],
    };
  }
}
