import { IEnSrvOptions } from "./IEnSrvOptions";
import { updateRequestOptions, send } from "./send";
import { EnoFactory } from "./EnoFactory";
import { switchMap, tap } from "rxjs/operators";
import nock from "nock";
import { firstValueFrom } from "rxjs";
import { OptionsOfTextResponseBody } from "got/dist/source";
import { ResponseHeaders } from "./models/types";
import { IQueryOption } from "./query";
import { AbortController } from "node-abort-controller";

describe("send", () => {
  let nockedSend: nock.Interceptor;

  beforeEach(() => {
    nock.cleanAll();
    nockedSend = nock("http://example.com")
      .post("/ensrv/")
      .query({ ns: "myNameSpace" });
  });

  it("should cancel the send on abort signal", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(200, [eno]);

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      abortController: new AbortController(),
    };

    send([], testOptions).subscribe({
      next: () => {
        fail();
        done();
      },
      error: (err) => {
        expect(err?.message).toBe('Request aborted');
        done();
      },
    });

    testOptions.abortController?.abort();
  });

  it("should not attempt the send if already cancelled", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(200, [eno]);

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      abortController: new AbortController(),
    };

    testOptions.abortController?.abort();

    send([], testOptions).subscribe({
      next: () => {
        fail();
        done();
      },
      error: (err) => {
        expect(err?.message).toBe('Request aborted');
        done();
      },
    });
  });

  it("should cancel the send on unsubscribe", () => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.times(1).reply(200, [eno]);

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
    };

    const obs = send([], testOptions);
    const sub1 = obs.subscribe({
      next: () => fail(),
      error: () => fail(),
    });

    const sub2 = obs.subscribe({
      next: () => fail(),
      error: () => fail(),
    });

    sub1.unsubscribe();
    sub2.unsubscribe();
  });

  it("should return enos", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(200, [eno]);

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
    };

    send([], testOptions).subscribe({
      next: (batch) => {
        expect(batch.length).toBe(1);
        expect(batch[0].tip).toBe(eno.tip);
        done();
      },
      error: () => {
        fail();
        done();
      }
    });
  });

  it("should return error", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(400, "Some return content");

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
    };

    send([], testOptions).subscribe({
      next: (batch) => {
        expect(batch.length).toBe(1);
        expect(batch[0].tip).toBe(eno.tip);
        fail();
      },
      error: (err) => {
        expect(err.message).toBe("Some return content");
        expect(err.code).toBe(400);
        done();
      },
    });
  });

  it("should set session token", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(200, [eno], { "session-token": ["mynewtoken"] });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      sessionToken: "myoldtoken",
      useCurrentSession: false,
    };

    send([], testOptions).subscribe({
      next: (_) => {
        expect(testOptions.sessionToken).toBe("mynewtoken");
        done();
      },
    });
  });

  it("should set session id", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(function () {
      expect(this.req.getHeader("Session-Id")).toBe("sample");
      return [200, [eno], { "Session-Id": [this.req.getHeader("Session-Id")] }];
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      sessionToken:
        "ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LmV5SnpaWE56YVc5dVZHOXJaVzRpT2lKMFpYTjBMM05sYzNOcGIyNVViMnRsYmlJc0luTmxjM05wYjI1SlpDSTZJbk5oYlhCc1pTSXNJbTVoYldWemNHRmpaU0k2SW5SbGMzUXZibUZ0WlhOd1lXTmxJaXdpWTNWemRHOXRVR0Y1Ykc5aFpDSTZleUoxYzJWeVZHbHdJam9pZEdWemRDOTFjMlZ5THpFaUxDSndjbTltYVd4bFZHbHdJam9pWVhCd0wzQnliMlpwYkdVdllXUnRhVzVwYzNSeVlYUnZjaUo5ZlEuUFQ1TnFSbHZvREZLcnlYYUVXakd6ZFJDbUNid01ONmdMOTJ6Y2MyQURJOA==",
    };

    send([], testOptions).subscribe({ next: () => done(), error: () => fail() });
  });

  it("should should use shared anonymous session", (done) => {
    nock("http://first")
      .post("/ensrv/")
      .query({ ns: "myNameSpace" })
      .reply(function (url) {
        // Expect no session token
        expect(this.req.getHeader("Session-Token")).toBeUndefined();
        return [200, [], { "Session-Token": "myFirstToken" }];
      });

    nock("http://second")
      .post("/ensrv/")
      .query({ ns: "myNameSpace" })
      .reply(function (url) {
        // Expect reuse of anonymous token because same namespace
        expect(this.req.getHeader("Session-Token")).toEqual("myFirstToken");
        return [
          200,
          [],
          { "Session-Token": this.req.getHeader("Session-Token") },
        ];
      });

    nock("http://third")
      .post("/ensrv/")
      .query({ ns: "anotherNameSpace" })
      .reply(function (url) {
        // Expect no session token because different namespace
        expect(this.req.getHeader("Session-Token")).toBeUndefined();
        return [200, [], { "Session-Token": "mySecondToken" }];
      });

    const testOptions: { [key: string]: IEnSrvOptions } = {
      first: {
        enSrvUrl: "http://first/ensrv/",
        namespace: "myNameSpace",
        useSharedAnonymousSession: true,
        useCurrentSession: false,
      },
      second: {
        enSrvUrl: "http://second/ensrv/",
        namespace: "myNameSpace",
        useSharedAnonymousSession: true,
        useCurrentSession: false,
      },
      third: {
        enSrvUrl: "http://third/ensrv/",
        namespace: "anotherNameSpace",
        useSharedAnonymousSession: true,
        useCurrentSession: false,
      },
    };

    send([], testOptions.first)
      .pipe(
        tap((_) => expect(testOptions.first.sessionToken).toBeUndefined()),
        switchMap((_) => send([], testOptions.second)),
        tap((_) => expect(testOptions.second.sessionToken).toBeUndefined()),
        switchMap((_) => send([], testOptions.third)),
        tap((_) => expect(testOptions.third.sessionToken).toBeUndefined())
      )
      .subscribe({ next: () => done(), error: () => fail() });
  });

  it("should send client ip and via headers", async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    let calledHeaders: any;
    nockedSend.reply(function () {
      calledHeaders = this.req.headers;
      return [200, [eno], {}];
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      clientIp: "1.2.3.4",
      clientVia: "my-via",
    };

    await firstValueFrom(send([], testOptions));

    expect(calledHeaders).toEqual(
      jasmine.objectContaining({
        "encloud-clientip": ["1.2.3.4"],
        "encloud-via": ["my-via"],
      })
    );
  });

  it("should use keep alives", async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    let req: any;
    nockedSend.reply(function () {
      req = this.req;
      return [200, [eno], {}];
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
    };

    await firstValueFrom(send([], testOptions));

    expect(req.options.agent.keepAlive).toBe(true);
  });

  it('should reuse agents', async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
    };

    let req1: any;
    nockedSend.reply(function () {
      req1 = this.req;
      return [200, [eno], {}];
    });
    await firstValueFrom(send([], testOptions));

    let req2: any;
    nockedSend.reply(function () {
      req2 = this.req;
      return [200, [eno], {}];
    });
    await firstValueFrom(send([], testOptions));

    expect(req1.options.agent).toBe(req2.options.agent);
  });

  it('should retry twice', async () => {
    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      bulk: true,
    };

    let numCalled = 0;
    // console.log(new Date().valueOf());
    nockedSend.times(3).reply(() => {
      // console.log(new Date().valueOf());
      numCalled++;
      return [502];
    });

    try {
      await firstValueFrom(send([], testOptions));
    } catch (err) {
      expect(err.code).toBe(502);
    }
    expect(numCalled).toBe(3);
  });

  it("should send the bulk header", async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    let calledHeaders: any;
    nockedSend.reply(function () {
      calledHeaders = this.req.headers;
      return [200, [eno], {}];
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      bulk: true,
    };

    await firstValueFrom(send([], testOptions));

    expect(calledHeaders).toEqual(
      jasmine.objectContaining({
        "encloud-bulk": ["true"],
      })
    );
  });

  it("should send additional headers", async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    let calledHeaders: any;
    nockedSend.reply(function () {
      calledHeaders = this.req.headers;
      return [200, [eno], {}];
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      additionalHeaders: {
        key1: ["value1"],
        key2: ["value2a", "value2b"],
        key3: [],
      },
    };

    await firstValueFrom(send([], testOptions));

    expect(calledHeaders).toEqual(
      jasmine.objectContaining({
        key1: ["value1"],
        key2: ["value2a", "value2b"],
        key3: [],
      })
    );
  });

  it("should send additional query string parameters", async () => {
    const enoFactory = new EnoFactory("mytype", "security/policy/local");
    const eno = enoFactory.makeEno();

    let calledUrl: string = '';
    nock("http://example.com")
      .post("/ensrv/")
      .query({
        ns: "myNameSpace",
        key1: "value1",
        "ke&y2": "val&ue2",
        key3: "",
      })
      .reply(function (url) {
        calledUrl = url;
        return [200, [eno], {}];
      });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      useCurrentSession: false,
      additionalQueryString: {
        key1: "value1",
        "ke&y2": "val&ue2",
        key3: "",
      },
    };

    await firstValueFrom(send([], testOptions));

    expect(calledUrl).toBe(
      "/ensrv/?ns=myNameSpace&key1=value1&ke%26y2=val%26ue2&key3="
    );
  });

  it("should update headers values", (done) => {
    const enoFactory = new EnoFactory("mytype");
    enoFactory.setSecurity("security/policy/local");
    const eno = enoFactory.makeEno();

    nockedSend.reply(200, [eno], {
      'en_query_nextpage': "searchAfterToken",
      'header2': "header2Value",
      'session-token': ["mynewtoken"],
    });

    const testOptions: IEnSrvOptions = {
      enSrvUrl: "http://example.com/ensrv/",
      namespace: "myNameSpace",
      sessionToken: "myoldtoken",
      useCurrentSession: false,
    };

    const queryOptions: IQueryOption = {
      extraAttributes: [{ label: "runtimeAttr1", formula: "TIP()" }],
      extraFilters: [{ label: "runtimeFilter1", formula: "TIP()" }],
      vars: {
        varKey1: ["varVal1a", "varVal1b"],
        varKey2: ["varVal2a", "varVal2b"],
      },
      dimensionOptions: [
        {
          label: "runtimeDim1",
          formula: "TIP()",
          sortby: ["TITLE()"],
          sortdir: ["asc"],
          limit: 1,
        },
      ],
      responseHeadersToInclude: ['en_query_nextpage', 'header2', 'header3']
    };
    send([], testOptions, queryOptions).subscribe({
      next: (_) => {
        expect(queryOptions.responseHeadersToInclude).toEqual([
          { en_query_nextpage: "searchAfterToken" },
          { header2: "header2Value" },
          { header3: null },
        ] as ResponseHeaders);
        done();
      },
    });
  });

  describe('#updateRequestOptions', () => {

    it('should use the query service', () => {
      const enoFactory = new EnoFactory("op/query", "security/policy/local");
      const eno = enoFactory.makeEno();
      const testOptions: IEnSrvOptions = { enSrvUrl: "http://example.com/ensrv/", namespace: "myNameSpace", useQueryService: true };
      let requestOptions: OptionsOfTextResponseBody = { json: [eno] };
      updateRequestOptions([eno], testOptions, requestOptions);
      expect(requestOptions.url).toBe('http://example.com/query/ensrv');
    });

    it('should not use the query service', () => {
      const enoFactory = new EnoFactory("op/query", "security/policy/local");
      const eno = enoFactory.makeEno();
      const testOptions: IEnSrvOptions = { enSrvUrl: "http://example.com/ensrv/", namespace: "myNameSpace" };
      let requestOptions: OptionsOfTextResponseBody = { json: [eno] };
      updateRequestOptions([eno], testOptions, requestOptions);
      expect(requestOptions.url).toBe('http://example.com/ensrv/op/query?ns=myNameSpace');
    });

    it('should use a thin dispatcher', () => {
      const enoFactory = new EnoFactory("op/pull", "security/policy/local");
      const eno = enoFactory.makeEno();
      const testOptions: IEnSrvOptions = { enSrvUrl: "http://example.com/ensrv/", namespace: "myNameSpace" };
      let requestOptions: OptionsOfTextResponseBody = { json: [eno] };
      updateRequestOptions([eno], testOptions, requestOptions);
      expect(requestOptions.url).toBe('http://example.com/ensrv/op/pull?ns=myNameSpace');
    });

    it('should use the fat dispatcher', () => {
      const enoFactory = new EnoFactory("op/process", "security/policy/local");
      const eno = enoFactory.makeEno();
      const testOptions: IEnSrvOptions = { enSrvUrl: "http://example.com/ensrv/", namespace: "myNameSpace" };
      let requestOptions: OptionsOfTextResponseBody = { json: [eno] };
      updateRequestOptions([eno], testOptions, requestOptions);
      expect(requestOptions.url).toBe('http://example.com/ensrv/?ns=myNameSpace');
    });

    it('should use the fat dispatcher because there is multiple enos in the batch', () => {
      const enoFactory = new EnoFactory("op/query", "security/policy/local");
      const eno = enoFactory.makeEno();
      const testOptions: IEnSrvOptions = { enSrvUrl: "http://example.com/ensrv/", namespace: "myNameSpace" };
      let requestOptions: OptionsOfTextResponseBody = { json: [eno, eno] };
      updateRequestOptions([eno, eno], testOptions, requestOptions);
      expect(requestOptions.url).toBe('http://example.com/ensrv/?ns=myNameSpace');
    });

  });

  describe("initial session token management", () => {
    let enoFactory: EnoFactory;
    let eno: any;

    beforeEach(() => {
      enoFactory = new EnoFactory("mytype", "security/policy/local");
      eno = enoFactory.makeEno();
    });

    describe("maintainInitialSessionToken flag", () => {
      it("should handle all session token scenarios", async () => {
        const testCases = [
          {
            description: "maintainInitialSessionToken is undefined (explicit)",
            inputOptions: {
              sessionToken: "existing-token",
              maintainInitialSessionToken: undefined,
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: undefined,
            expectedSessionToken: "response-token",
          },
          {
            description: "maintainInitialSessionToken is undefined (implicit)",
            inputOptions: {
              sessionToken: "existing-token",
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: undefined,
            expectedSessionToken: "response-token",
          },
          {
            description: "maintainInitialSessionToken is false",
            inputOptions: {
              sessionToken: "existing-token",
              maintainInitialSessionToken: false,
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: undefined,
            expectedSessionToken: "response-token",
          },
          {
            description: "maintainInitialSessionToken is true with explicit sessionToken",
            inputOptions: {
              sessionToken: "existing-token",
              maintainInitialSessionToken: true,
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: "existing-token",
            expectedSessionToken: "response-token",
          },
          {
            description: "populate from response header when no sessionToken",
            inputOptions: {
              maintainInitialSessionToken: true,
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: "response-token",
            expectedSessionToken: "response-token",
          },
          {
            description: "preserve existing initialSessionToken (explicit sessionToken)",
            inputOptions: {
              sessionToken: "new-token",
              maintainInitialSessionToken: true,
              initialSessionToken: "preserved-token",
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: "preserved-token",
            expectedSessionToken: "response-token",
          },
          {
            description: "preserve existing initialSessionToken (response only)",
            inputOptions: {
              maintainInitialSessionToken: true,
              initialSessionToken: "preserved-token",
            },
            responseHeaders: { "session-token": ["response-token"] },
            expectedInitialSessionToken: "preserved-token",
            expectedSessionToken: "response-token",
          },
          {
            description: "populate from response header (string format)",
            inputOptions: {
              maintainInitialSessionToken: true,
            },
            responseHeaders: { "session-token": "string-response-token" },
            expectedInitialSessionToken: "string-response-token",
            expectedSessionToken: "string-response-token",
          },
          {
            description: "populate from response header (array format)",
            inputOptions: {
              maintainInitialSessionToken: true,
            },
            responseHeaders: { "session-token": ["token1"] },
            expectedInitialSessionToken: "token1",
            expectedSessionToken: "token1",
          },

          // Edge Cases
          {
            description: "handle undefined sessionToken",
            inputOptions: {
              sessionToken: undefined,
              maintainInitialSessionToken: true,
            },
            responseHeaders: {},
            expectedInitialSessionToken: undefined,
            expectedSessionToken: undefined,
          },
          {
            description: "handle empty array response headers",
            inputOptions: {
              maintainInitialSessionToken: true,
            },
            responseHeaders: { "session-token": [] },
            expectedInitialSessionToken: undefined,
            expectedSessionToken: undefined,
          },
        ];

        for (const testCase of testCases) {
          // Setup fresh nock for each test case
          nock.cleanAll();
          const testNock = nock("http://example.com")
            .post("/ensrv/")
            .query({ ns: "myNameSpace" })
            .reply(200, [eno], testCase.responseHeaders);

          // Create test options by merging base options with test case input
          const testOptions: IEnSrvOptions = {
            enSrvUrl: "http://example.com/ensrv/",
            namespace: "myNameSpace",
            useCurrentSession: false,
            ...testCase.inputOptions,
          };

          await firstValueFrom(send([], testOptions));

          // Assert both initialSessionToken and sessionToken values
          expect(testOptions.initialSessionToken)
            .withContext(`${testCase.description} - initialSessionToken`)
            .toBe(testCase.expectedInitialSessionToken);

          expect(testOptions.sessionToken)
            .withContext(`${testCase.description} - sessionToken`)
            .toBe(testCase.expectedSessionToken);
        }
      });

      it("should handle shared anonymous session scenarios", async () => {
        const sessionTokenCache = require("./sessionTokenCache");

        // Test case: populate from cached token with shared anonymous session
        spyOn(sessionTokenCache, "hasToken").and.returnValue(true);
        spyOn(sessionTokenCache, "getToken").and.returnValue("cached-token");
        spyOn(sessionTokenCache, "setToken");

        nock.cleanAll();
        nock("http://example.com")
          .post("/ensrv/")
          .query({ ns: "myNameSpace" })
          .reply(200, [eno], { "session-token": ["response-token"] });

        const testOptions: IEnSrvOptions = {
          enSrvUrl: "http://example.com/ensrv/",
          namespace: "myNameSpace",
          useCurrentSession: false,
          maintainInitialSessionToken: true,
          useSharedAnonymousSession: true,
        };

        await firstValueFrom(send([], testOptions));

        expect(testOptions.initialSessionToken).toBe("cached-token");
        expect(testOptions.sessionToken).toBeUndefined(); // sessionToken stays undefined with useSharedAnonymousSession
        expect(sessionTokenCache.setToken).toHaveBeenCalledWith("myNameSpace", "response-token");
      });

      it("should ignore cache when maintainInitialSessionToken is false", async () => {
        const sessionTokenCache = require("./sessionTokenCache");

        spyOn(sessionTokenCache, "hasToken").and.returnValue(true);
        spyOn(sessionTokenCache, "getToken").and.returnValue("cached-token");
        spyOn(sessionTokenCache, "setToken");

        nock.cleanAll();
        nock("http://example.com")
          .post("/ensrv/")
          .query({ ns: "myNameSpace" })
          .reply(200, [eno], { "session-token": ["response-token"] });

        const testOptions: IEnSrvOptions = {
          enSrvUrl: "http://example.com/ensrv/",
          namespace: "myNameSpace",
          useCurrentSession: false,
          maintainInitialSessionToken: false,
          useSharedAnonymousSession: true,
        };

        await firstValueFrom(send([], testOptions));

        expect(testOptions.initialSessionToken).toBeUndefined();
        expect(testOptions.sessionToken).toBeUndefined(); // sessionToken stays undefined with useSharedAnonymousSession
        expect(sessionTokenCache.setToken).toHaveBeenCalledWith("myNameSpace", "response-token");
      });
    });

    describe("Specialized Scenarios", () => {
      let sessionTokenCache: any;

      beforeEach(() => {
        sessionTokenCache = require("./sessionTokenCache");
        spyOn(sessionTokenCache, "hasToken").and.returnValue(false);
        spyOn(sessionTokenCache, "getToken");
        spyOn(sessionTokenCache, "setToken");
      });

      it("should preserve initialSessionToken across multiple requests", async () => {
        // First request
        nockedSend.reply(200, [eno], { "session-token": ["first-response-token"] });

        const testOptions: IEnSrvOptions = {
          enSrvUrl: "http://example.com/ensrv/",
          namespace: "myNameSpace",
          sessionToken: "initial-token",
          useCurrentSession: false,
          maintainInitialSessionToken: true,
        };

        await firstValueFrom(send([], testOptions));
        expect(testOptions.initialSessionToken).toBe("initial-token");

        // Second request with different response token
        nockedSend.reply(200, [eno], { "session-token": ["second-response-token"] });
        await firstValueFrom(send([], testOptions));

        expect(testOptions.initialSessionToken).toBe("initial-token");
        expect(sessionTokenCache.getToken).not.toHaveBeenCalled();
        expect(sessionTokenCache.setToken).not.toHaveBeenCalled();
      });

      it("should preserve initialSessionToken when cache changes", async () => {
        sessionTokenCache.hasToken.and.returnValue(true);
        sessionTokenCache.getToken.and.returnValue("original-cached-token");

        nockedSend.reply(200, [eno], { "session-token": ["response-token"] });

        const testOptions: IEnSrvOptions = {
          enSrvUrl: "http://example.com/ensrv/",
          namespace: "myNameSpace",
          useCurrentSession: false,
          maintainInitialSessionToken: true,
          useSharedAnonymousSession: true,
        };

        // First request
        await firstValueFrom(send([], testOptions));
        expect(testOptions.initialSessionToken).toBe("original-cached-token");

        // Simulate cache change
        sessionTokenCache.getToken.and.returnValue("new-cached-token");

        // Second request
        nockedSend.reply(200, [eno], { "session-token": ["another-response-token"] });
        await firstValueFrom(send([], testOptions));

        expect(testOptions.initialSessionToken).toBe("original-cached-token");
      });
    });
  });

});
