import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import {
  ALL_VIEW,
  CORE_NETWORK_VIEW,
  CORE_VIEW,
  DEFAULT_DETAIL_VIEW,
  formatAgeSeconds,
  formatKstIso,
  matchesCore,
  matchesNetwork,
  normalize,
} from './zabbix-utils';
import { ZabbixClientService } from './zabbix-client.service';

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

  async listHosts(
    orgIdHeader?: string
  ): Promise<{ hosts: string[]; rows: Array<{ text: string; value: string }> }> {
    const result = await this.zabbixClient.fetchHosts(
      {
        output: ['hostid', 'name', 'host'],
        sortfield: 'name',
      },
      orgIdHeader
    );

    const hosts = result
      .map((entry) => entry.host || entry.name)
      .filter((host): host is string => Boolean(host))
      .sort((a, b) => a.localeCompare(b));

    const rows = hosts.map((host) => ({ text: host, value: host }));

    return { hosts, rows };
  }

  async getHostDetail(
    orgIdHeader?: string,
    hostName?: string,
    view?: string,
    contains?: string
  ): Promise<{ host: string; rows: Array<Record<string, string | number | 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', 'name', 'key_', 'lastvalue', 'lastclock', 'units'],
        hostids: [host.hostid],
        sortfield: 'name',
      },
      orgIdHeader
    );

    const viewMode = normalize(view) || DEFAULT_DETAIL_VIEW;
    const containsTerm = normalize(contains);

    const rows = items
      .filter((item) => {
        const inScope =
          viewMode === ALL_VIEW
            ? true
            : viewMode === CORE_VIEW
              ? matchesCore(item)
              : viewMode === CORE_NETWORK_VIEW
                ? matchesCore(item) || matchesNetwork(item)
                : matchesCore(item) || matchesNetwork(item);

        if (!inScope) return false;

        if (!containsTerm) return true;

        const name = normalize(item.name);
        const key = normalize(item.key_);
        return name.includes(containsTerm) || key.includes(containsTerm);
      })
      .map((item) => ({
        name: item.name,
        key: item.key_,
        lastvalue: item.lastvalue ?? null,
        units: item.units ?? null,
        value_display:
          item.lastvalue == null
            ? null
            : item.units
              ? `${item.lastvalue} ${item.units}`.trim()
              : `${item.lastvalue}`,
        lastclock: item.lastclock ?? null,
        lastclock_kst: formatKstIso(item.lastclock),
        last_seen_human: formatAgeSeconds(item.lastclock),
      }));

    return { host: host.host || host.name || hostName, rows };
  }
}
