import { replicaField } from "./replication.service";

/**
 * Verbatim shape of `SHOW REPLICA STATUS\G` from the live replica, trimmed to
 * the fields the panel reads plus the neighbours that matter.
 *
 * The empty `Last_SQL_Error:` immediately followed by
 * `Replicate_Ignore_Server_Ids:` is the whole point of the fixture — that exact
 * adjacency is what the first implementation misread.
 */
const HEALTHY = [
  "*************************** 1. row ***************************",
  "             Replica_IO_State: Waiting for source to send event",
  "                  Source_Host: 100.103.77.46",
  "                  Source_User: repl",
  "           Replica_IO_Running: Yes",
  "          Replica_SQL_Running: Yes",
  "              Replicate_Do_DB: ",
  "                   Last_Errno: 0",
  "                   Last_Error: ",
  "        Seconds_Behind_Source: 0",
  "                Last_IO_Errno: 0",
  "                Last_IO_Error: ",
  "               Last_SQL_Errno: 0",
  "               Last_SQL_Error: ",
  "  Replicate_Ignore_Server_Ids: ",
  "             Source_Server_Id: 1",
].join("\n");

const BROKEN = [
  "           Replica_IO_Running: Yes",
  "          Replica_SQL_Running: No",
  "        Seconds_Behind_Source: NULL",
  "                Last_IO_Error: ",
  "               Last_SQL_Error: Could not execute Write_rows event on table jorgecuadros.customers",
  "  Replicate_Ignore_Server_Ids: ",
].join("\n");

describe("replicaField", () => {
  it("reads plain values", () => {
    expect(replicaField(HEALTHY, "Replica_IO_Running")).toBe("Yes");
    expect(replicaField(HEALTHY, "Replica_SQL_Running")).toBe("Yes");
    expect(replicaField(HEALTHY, "Source_Host")).toBe("100.103.77.46");
    expect(replicaField(HEALTHY, "Seconds_Behind_Source")).toBe("0");
  });

  /**
   * The regression this file exists for. `\s` matches newlines in JavaScript,
   * so `^\s*NAME:\s*(.*)$` walks past an empty field's line break and captures
   * the NEXT line — turning a healthy replica into
   * "Error SQL: Replicate_Ignore_Server_Ids:" in the admin panel.
   */
  it("returns null for an empty field instead of the following line", () => {
    expect(replicaField(HEALTHY, "Last_SQL_Error")).toBeNull();
    expect(replicaField(HEALTHY, "Last_IO_Error")).toBeNull();
    expect(replicaField(HEALTHY, "Last_Error")).toBeNull();
    expect(replicaField(HEALTHY, "Replicate_Do_DB")).toBeNull();
    expect(replicaField(HEALTHY, "Replicate_Ignore_Server_Ids")).toBeNull();
  });

  it("still reads a real error when there is one", () => {
    expect(replicaField(BROKEN, "Last_SQL_Error")).toBe(
      "Could not execute Write_rows event on table jorgecuadros.customers",
    );
    expect(replicaField(BROKEN, "Replica_SQL_Running")).toBe("No");
  });

  /** NULL is a distinct state from empty and must survive as the literal. */
  it("preserves the literal NULL that MySQL prints for unknown lag", () => {
    expect(replicaField(BROKEN, "Seconds_Behind_Source")).toBe("NULL");
  });

  it("returns null for a field that is not present at all", () => {
    expect(replicaField(HEALTHY, "Nonexistent_Field")).toBeNull();
  });

  /**
   * Field names are matched at the start of a line. Without the line anchor,
   * "Last_Error" would also match inside "Last_SQL_Error" and read the wrong
   * value — the two carry different things and both feed the panel.
   */
  it("does not match a field name that is a suffix of another", () => {
    const raw = "               Last_SQL_Error: boom\n                   Last_Error: ";
    expect(replicaField(raw, "Last_Error")).toBeNull();
    expect(replicaField(raw, "Last_SQL_Error")).toBe("boom");
  });
});
