import beeline from "honeycomb-beeline";
import fetch from "node-fetch";

function capitalize(str) {
  return str[0].toUpperCase() + str.slice(1);
}

function getPoseFromPetState(petState) {
  const { moodId, female, unconverted } = petState;

  if (unconverted) {
    return "UNCONVERTED";
  } else if (moodId == null || female == null) {
    return "UNKNOWN";
  } else if (String(moodId) === "1" && String(female) === "0") {
    return "HAPPY_MASC";
  } else if (String(moodId) === "1" && String(female) === "1") {
    return "HAPPY_FEM";
  } else if (String(moodId) === "2" && String(female) === "0") {
    return "SAD_MASC";
  } else if (String(moodId) === "2" && String(female) === "1") {
    return "SAD_FEM";
  } else if (String(moodId) === "4" && String(female) === "0") {
    return "SICK_MASC";
  } else if (String(moodId) === "4" && String(female) === "1") {
    return "SICK_FEM";
  } else {
    throw new Error(
      `could not identify pose: ` +
        `moodId=${moodId}, ` +
        `female=${female}, ` +
        `unconverted=${unconverted}`,
    );
  }
}

function getPetStateFieldsFromPose(pose) {
  if (pose === "UNCONVERTED") {
    return { moodId: null, female: null, unconverted: true, labeled: true };
  } else if (pose === "UNKNOWN") {
    return { moodId: null, female: null, unconverted: false, labeled: false };
  } else if (pose === "HAPPY_MASC") {
    return { moodId: "1", female: false, unconverted: false, labeled: true };
  } else if (pose === "HAPPY_FEM") {
    return { moodId: "1", female: true, unconverted: false, labeled: true };
  } else if (pose === "SAD_MASC") {
    return { moodId: "2", female: false, unconverted: false, labeled: true };
  } else if (pose === "SAD_FEM") {
    return { moodId: "2", female: true, unconverted: false, labeled: true };
  } else if (pose === "SICK_MASC") {
    return { moodId: "4", female: false, unconverted: false, labeled: true };
  } else if (pose === "SICK_FEM") {
    return { moodId: "4", female: true, unconverted: false, labeled: true };
  } else {
    throw new Error(`unexpected pose ${pose}`);
  }
}

const POSE_NAMES = {
  HAPPY_MASC: "Happy Masc",
  SAD_MASC: "Sad Masc",
  SICK_MASC: "Sick Masc",
  HAPPY_FEM: "Happy Fem",
  SAD_FEM: "Sad Fem",
  SICK_FEM: "Sick Fem",
  UNCONVERTED: "Unconverted",
  UNKNOWN: "Unknown",
};

function getPoseName(pose) {
  return POSE_NAMES[pose];
}

function getRestrictedZoneIds(zonesRestrict) {
  const restrictedZoneIds = [];
  for (const [i, bit] of Array.from(zonesRestrict).entries()) {
    if (bit === "1") {
      restrictedZoneIds.push(i + 1);
    }
  }
  return restrictedZoneIds;
}

async function loadBodyName(bodyId, db) {
  if (String(bodyId) === "0") {
    return "All bodies";
  }

  const [rows] = await db.execute(
    `SELECT pt.body_id, s.name AS species_name,
        c.name AS color_name, c.standard FROM pet_types pt
      INNER JOIN species s ON pt.species_id = s.id
      INNER JOIN colors c ON c.id = pt.color_id
      WHERE pt.body_id = ?
      ORDER BY c.standard DESC, color_name, species_name LIMIT 1;`,
    [bodyId],
  );
  const row = normalizeRow(rows[0]);
  const speciesName = capitalize(row.speciesName);
  const colorName = row.standard ? "Standard" : capitalize(row.colorName);
  return `${colorName} ${speciesName}`;
}

async function logToDiscord(body) {
  const span = beeline.startSpan({ name: "logToDiscord" });

  try {
    const res = await fetch(process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"], {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    if (!res.ok) {
      const resText = await res.text();
      throw new Error(
        `Discord returned ${res.status} ${res.statusText}: ${resText}`,
      );
    }
  } finally {
    beeline.finishSpan(span);
  }
}

function normalizeRow(row) {
  const normalizedRow = {};
  for (let [key, value] of Object.entries(row)) {
    key = key.replace(/_([a-z])/gi, (m) => m[1].toUpperCase());
    if ((key === "id" || key.endsWith("Id")) && typeof value === "number") {
      value = String(value);
    }
    normalizedRow[key] = value;
  }
  return normalizedRow;
}

module.exports = {
  capitalize,
  getPoseFromPetState,
  getPetStateFieldsFromPose,
  getPoseName,
  getRestrictedZoneIds,
  loadBodyName,
  logToDiscord,
  normalizeRow,

  // For Apollo's @cacheControl maxAge: time in seconds.
  oneWeek: 604800,
  oneDay: 86400,
  oneHour: 3600,
  oneMinute: 60,
};