import {
  DeviceConfigAckEntity,
  DeviceConfigEntity,
  getLatestDeviceConfigAck,
  toDeviceConfigAckPayload,
  toDeviceConfigPayload
} from "../store/deviceConfigStore";
import { listHeartbeats } from "../store/heartbeatStore";
import { listMqttMessages, toMqttMessagePayload } from "../store/mqttMessageStore";

type ConfigDriftStatus = "applied" | "pending_ack" | "failed_ack" | "stale_ack" | "pulled_not_pushed" | "never_pushed";

function deriveConfigDriftStatus(config: DeviceConfigEntity, latestAck: DeviceConfigAckEntity | null): ConfigDriftStatus {
  if (!latestAck) {
    return "pending_ack";
  }

  if (latestAck.config_version < config.config_version) {
    return "stale_ack";
  }

  if (latestAck.config_version > config.config_version) {
    return "pending_ack";
  }

  if (latestAck.status === "failed") {
    return "failed_ack";
  }

  return "applied";
}

export async function buildDeviceConfigStatus(config: DeviceConfigEntity) {
  const latestAck = await getLatestDeviceConfigAck(config.device_id);
  const latestPush = (
    await listMqttMessages({
      device_id: config.device_id,
      direction: "downlink",
      message_type: "config_push",
      correlation_id: `config:${config.config_version}`,
      limit: 1
    })
  )[0];
  const latestConfigPull = (
    await listHeartbeats({
      device_id: config.device_id,
      state: "config_pull",
      limit: 1
    })
  )[0];

  const driftStatus = latestPush ? deriveConfigDriftStatus(config, latestAck) : latestConfigPull ? "pulled_not_pushed" : "never_pushed";

  return {
    device_id: config.device_id,
    config: toDeviceConfigPayload(config),
    drift_status: driftStatus,
    desired_config_version: config.config_version,
    latest_ack: latestAck ? toDeviceConfigAckPayload(latestAck) : null,
    latest_push: latestPush ? toMqttMessagePayload(latestPush) : null,
    latest_config_pull: latestConfigPull || null,
    retry_recommended: !["applied", "pulled_not_pushed"].includes(driftStatus)
  };
}
