/*
 * Copyright 2023 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { $Objects, Employee, FooInterface } from "@osdk/client.test.ontology";
import { LegacyFauxFoundry, startNodeApiServer, stubData, withoutRid } from "@osdk/shared.test";
import { beforeAll, describe, expect, expectTypeOf, it } from "vitest";
import { additionalContext } from "../Client.js";
import { createClient } from "../createClient.js";
import { InterfaceDefinitions } from "../ontology/OntologyProvider.js";
import { createOsdkObject } from "./convertWireToOsdkObjects/createOsdkObject.js";
function asV2Object(o, includeRid) {
  o = includeRid ? {
    ...o
  } : withoutRid(o);
  o.$apiName = o.__apiName;
  o.$objectType = o.__apiName;
  o.$primaryKey = o.__primaryKey;
  o.$title = o.__title;
  delete o.__apiName;
  delete o.__primaryKey;
  delete o.__title;
  return o;
}
describe.each(["https://stack.palantir.com", "https://stack.palantirCustom.com/foo/first/someStuff"])("OsdkObject for %s", baseUrl => {
  let client;
  beforeAll(async () => {
    let apiServer;
    ({
      client,
      apiServer
    } = startNodeApiServer(new LegacyFauxFoundry(baseUrl), createClient));
    return () => {
      apiServer.close();
    };
  });
  describe("link", () => {
    it("loads an employee", async () => {
      const result = await client(Employee).where({
        employeeId: stubData.employee1.employeeId
      }).fetchPage();

      // we should get the employee we requested
      const employee = result.data[0];
      expect(JSON.stringify(employee)).toBeDefined();
      expect(employee).toMatchObject({
        "$apiName": "Employee",
        "$objectType": "Employee",
        "$primaryKey": 50030,
        "class": "Red",
        "employeeId": 50030,
        "employeeStatus": expect.anything(),
        "fullName": "John Doe",
        "office": "NYC",
        "startDate": "2019-01-01"
      });
      employee.startDate;

      // it should have the prototype that we assign at hydration time
      expect(Object.keys(employee.$link.lead)).toBeDefined();
    });
    it("loads an employee with custom client", async () => {
      const result = await client(Employee).where({
        employeeId: stubData.employee1.employeeId
      }).fetchPage();

      // we should get the employee we requested
      const employee = result.data[0];
      expect(JSON.stringify(employee)).toBeDefined();
      expect(employee).toMatchObject({
        "$apiName": "Employee",
        "$objectType": "Employee",
        "$primaryKey": 50030,
        "class": "Red",
        "employeeId": 50030,
        "employeeStatus": expect.anything(),
        "fullName": "John Doe",
        "office": "NYC",
        "startDate": "2019-01-01"
      });
      employee.startDate;

      // it should have the prototype that we assign at hydration time
      expect(Object.keys(employee.$link.lead)).toBeDefined();
    });
    it("traverses the link from an employee to their lead", async () => {
      const result = await client(Employee).where({
        employeeId: stubData.employee1.employeeId
      }).fetchPage();
      const employee = result.data[0];
      const lead = await employee.$link.lead.fetchOne({
        $select: ["employeeId"]
      });
      expect(lead.employeeId).toBe(stubData.employee2.employeeId);

      // ensure that the select was performed
      expect(lead.employeeId).toBeDefined();
      expect(lead.employeeStatus).toBeUndefined();
    });
    it("traverses the link from an lead to their peeps", async () => {
      // slightly weird request here to hit the existing mocks for employee2
      const employees = await client(Employee).where({
        $and: [{
          "employeeId": {
            "$gt": 50030
          }
        }, {
          "employeeId": {
            "$lt": 50032
          }
        }]
      }).fetchPage();
      const lead = employees.data[0];
      expect(lead).toBeDefined();
      const peepsResult = await lead.$link.peeps.fetchPage({
        $select: ["fullName", "employeeId"]
      });
      expect(peepsResult.data).toHaveLength(2);
      expect(peepsResult.nextPageToken).toBeUndefined();

      // ensure that the select was performed
      expect(peepsResult.data[0].employeeId).toBeDefined();
      expect(peepsResult.data[0].office).toBeUndefined();
    });
    it("traverses the link from an lead to their peep by primaryKey with fetchOne", async () => {
      // slightly weird request here to hit the existing mocks for employee2
      const employees = await client(Employee).where({
        $and: [{
          "employeeId": {
            "$gt": 50030
          }
        }, {
          "employeeId": {
            "$lt": 50032
          }
        }]
      }).fetchPage();
      const lead = employees.data[0];
      expect(lead).toBeDefined();
      const peep = await lead.$link.peeps.fetchOne(stubData.employee1.employeeId, {
        $select: ["employeeId"]
      });
      expect(peep).toBeDefined();

      // ensure that select worked
      expect(peep.employeeId).toBeDefined();
      expect(peep.employeeStatus).toBeUndefined();
    });
    it("gives $rid access when requested", async () => {
      const result = await client(Employee).where({
        employeeId: stubData.employee1.employeeId
      }).fetchPage({
        $includeRid: true
      });
      const leadRid = result.data[0].$rid;
      expect(leadRid).toBeDefined();
      expect(leadRid).toBe("ri.phonograph2-objects.main.object.88a6fccb-f333-46d6-a07e-7725c5f18b61");
    });
    it("objects are enumerable in an sdk", async () => {
      const objects = Object.keys($Objects);
      expect(objects.sort()).toStrictEqual(["BgaoNflPlayer", "Employee", "ObjectWithTimestampPrimaryKey", "Office", "Person", "Task", "Todo", "equipment", "objectTypeWithAllPropertyTypes"].sort());
    });
  });
  describe("clone", () => {
    let employee;
    beforeAll(async () => {
      employee = (await client(Employee).where({
        employeeId: stubData.employee2.employeeId
      }).fetchPage()).data[0];
      expect(employee).toMatchObject({
        "$apiName": "Employee",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "Jane Doe",
        "class": "Blue",
        "employeeId": 50031,
        "fullName": "Jane Doe",
        "office": "SEA",
        "startDate": "2012-02-12"
      });
    });
    it("clones and updates an object with another osdk object", async () => {
      const updatedEmployee = createOsdkObject(client[additionalContext], {
        "apiName": "Employee",
        "primaryKeyType": "integer",
        "primaryKeyApiName": "employeeId",
        "properties": {
          "class": {
            "type": "string"
          },
          "employeeId": {
            "type": "integer"
          },
          "fullName": {
            "type": "string"
          },
          "office": {
            "type": "string"
          }
        }
      }, {
        "$apiName": "Employee",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "Jane Doe",
        "class": "Red",
        "employeeId": 50031,
        "fullName": "Jane Doe",
        "office": "NYC"
      });
      const mergedEmployee = employee.$clone(updatedEmployee);
      expectTypeOf(mergedEmployee).toEqualTypeOf(employee);
      expect(mergedEmployee).toMatchObject({
        "$apiName": "Employee",
        "$objectSpecifier": "Employee:50031",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "Jane Doe",
        "class": "Red",
        "employeeId": 50031,
        "employeeLocation": {
          "lastFetchedValue": undefined
        },
        "employeeSensor": {},
        "employeeStatus": {},
        "fullName": "Jane Doe",
        "office": "NYC",
        "startDate": "2012-02-12"
      });
    });
    it("correctly scopes up with another OSDK object", async () => {
      expectTypeOf({
        $clone: () => {}
      }.$clone(employee)).toMatchTypeOf();
    });
    it("Correctly preserves keys from original and new with distinct property key sets", async () => {
      expectTypeOf({
        $clone: () => {}
      }.$clone({})).toMatchTypeOf();
    });
    it("clones and updates an object with a record", async () => {
      const mergedEmployee = employee.$clone({
        "class": "Green",
        "employeeId": 50031,
        "fullName": "John Doe",
        "office": "SEA",
        "startDate": "2019-01-01"
      });
      expect(mergedEmployee).toMatchObject({
        "$apiName": "Employee",
        "$objectSpecifier": "Employee:50031",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "John Doe",
        "class": "Green",
        "employeeId": 50031,
        "employeeLocation": {
          "lastFetchedValue": undefined
        },
        "employeeSensor": {},
        "employeeStatus": {},
        "fullName": "John Doe",
        "office": "SEA",
        "startDate": "2019-01-01"
      });
    });
    it("correctly scopes up with a record", async () => {
      expectTypeOf({
        $clone: () => {}
      }.$clone({
        "class": "Green",
        "employeeId": 50031,
        "fullName": "John Doe",
        "office": "SEA",
        "startDate": "2019-01-01"
      })).toMatchTypeOf();
    });
    it("correctly sets title", async () => {
      const mergedEmployee = employee.$clone({
        "fullName": "Brad Pitt"
      });
      expect(mergedEmployee).toMatchObject({
        "$apiName": "Employee",
        "$objectSpecifier": "Employee:50031",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "Brad Pitt",
        "class": "Blue",
        "employeeId": 50031,
        "employeeLocation": {
          "lastFetchedValue": undefined
        },
        "employeeSensor": {},
        "employeeStatus": {},
        "fullName": "Brad Pitt",
        "office": "SEA",
        "startDate": "2012-02-12"
      });
    });
    it("is able to clone with nothing passed in", async () => {
      expect(employee.$clone()).toMatchObject({
        "$apiName": "Employee",
        "$objectType": "Employee",
        "$primaryKey": 50031,
        "$title": "Jane Doe",
        "class": "Blue",
        "employeeId": 50031,
        "fullName": "Jane Doe",
        "office": "SEA",
        "startDate": "2012-02-12"
      });
    });
    it("throws when merging objects with different primary keys", async () => {
      expect(() => employee.$clone({
        "class": "Green",
        "employeeId": 50035
      })).toThrow();
    });
    describe("interface", () => {
      const interfaceDef = {
        apiName: "FooInterface",
        displayName: "",
        links: {},
        properties: {
          "fooSpt": {
            type: "string"
          },
          "notImplementedFooSpt": {
            type: "string"
          }
        },
        rid: "",
        type: "interface",
        implements: [],
        description: undefined
      };
      const fooInterfaceOsdkDef = {
        apiName: "FooInterface",
        type: "interface",
        "__DefinitionMetadata": interfaceDef
      };
      const EmployeeFetchedMetadata = {
        "apiName": "Employee",
        "primaryKeyType": "integer",
        "primaryKeyApiName": "employeeId",
        "properties": {
          "employeeId": {
            "type": "integer"
          },
          "fullName": {
            "type": "string"
          }
        },
        interfaceMap: {
          "FooInterface": {
            "fooSpt": "fullName"
          }
        },
        inverseInterfaceMap: {
          "FooInterface": {
            "fullName": "fooSpt"
          }
        },
        [InterfaceDefinitions]: {
          "FooInterface": {
            def: interfaceDef
          }
        },
        type: "object",
        titleProperty: "fullName",
        pluralDisplayName: "",
        status: "ACTIVE",
        displayName: "",
        links: {},
        rid: "",
        icon: undefined,
        visibility: undefined,
        description: undefined
      };
      it("Correctly updates the interface and underlying object", () => {
        const employeeOsdkObject = createOsdkObject(client[additionalContext], EmployeeFetchedMetadata, {
          "$apiName": "Employee",
          "$objectType": "Employee",
          "$primaryKey": 50031,
          "$title": "Jane Doe",
          "employeeId": 50031,
          "fullName": "Jane Doe"
        });
        const personInterfaceObject = employeeOsdkObject.$as(fooInterfaceOsdkDef);
        const clonedInterface = personInterfaceObject.$clone({
          "fooSpt": "John Adams"
        });
        expect(clonedInterface).toMatchObject({
          "$apiName": "FooInterface",
          "$objectSpecifier": "Employee:50031",
          "$objectType": "Employee",
          "$primaryKey": 50031,
          "$title": "John Adams",
          "fooSpt": "John Adams"
        });
        expect(clonedInterface.$as("Employee")).toMatchObject({
          "$apiName": "Employee",
          "$objectSpecifier": "Employee:50031",
          "$objectType": "Employee",
          "$primaryKey": 50031,
          "$title": "John Adams",
          "employeeId": 50031,
          "fullName": "John Adams"
        });
      });
      it("Throws if updating an interface with a property not implemented by the underlying object type", () => {
        const employeeOsdkObject = createOsdkObject(client[additionalContext], EmployeeFetchedMetadata, {
          "$apiName": "Employee",
          "$objectType": "Employee",
          "$primaryKey": 50031,
          "$title": "Jane Doe",
          "employeeId": 50031,
          "fullName": "Jane Doe"
        });
        const loadedInterfaceObject = employeeOsdkObject.$as(interfaceDef);
        expect(() => loadedInterfaceObject.$clone({
          "notImplementedFooSpt": "John Adams"
        })).toThrowError(`Cannot clone interface with notImplementedFooSpt as property is not implemented by the underlying object type Employee`);
      });
    });
  });
  describe("objectSpecifier", () => {
    it("returns the object specifier for a loaded object", async () => {
      const result = await client(Employee).where({
        employeeId: stubData.employee1.employeeId
      }).fetchPage();
      const employee = result.data[0];
      expect(employee.$objectSpecifier).toBe("Employee:50030");
    });
    it("returns the object specifier for a loaded interface object", async () => {
      const result = await client(FooInterface).fetchPage();
      const object = result.data[0];
      expect(object.$objectSpecifier).toBe("Employee:50030");
    });
  });
  describe("$propertySecurities", () => {
    it("processes objects with secured property values correctly", async () => {
      const object = await client(Employee).fetchOne(20003, {
        $loadPropertySecurityMetadata: true
      });
      expectTypeOf(object.$propertySecurities).toMatchObjectType();
      expectTypeOf(object.$propertySecurities.class).toMatchTypeOf();
      expectTypeOf(object.$propertySecurities.favoriteRestaurants).toMatchTypeOf();
      expect(object).toMatchInlineSnapshot(`
        {
          "$apiName": "Employee",
          "$objectSpecifier": "Employee:20003",
          "$objectType": "Employee",
          "$primaryKey": 20003,
          "$propertySecurities": {
            "class": [
              {
                "type": "errorComputingSecurity",
              },
            ],
            "employeeId": [
              {
                "conjunctive": [
                  "CONFIDENTIAL",
                  "INTERNAL",
                ],
                "containerConjunctive": undefined,
                "containerDisjunctive": undefined,
                "disjunctive": [
                  [
                    "SECRET",
                  ],
                  [
                    "TOP_SECRET",
                  ],
                ],
                "type": "propertyMarkings",
              },
            ],
            "favoriteRestaurants": [
              [
                {
                  "type": "unsupportedPolicy",
                },
              ],
              [
                {
                  "conjunctive": [
                    "CONFIDENTIAL",
                    "INTERNAL",
                  ],
                  "containerConjunctive": undefined,
                  "containerDisjunctive": undefined,
                  "disjunctive": [
                    [
                      "SECRET",
                    ],
                    [
                      "TOP_SECRET",
                    ],
                  ],
                  "type": "propertyMarkings",
                },
              ],
            ],
            "fullName": [
              {
                "conjunctive": [
                  "CONFIDENTIAL",
                  "INTERNAL",
                ],
                "containerConjunctive": undefined,
                "containerDisjunctive": undefined,
                "disjunctive": [
                  [
                    "SECRET",
                  ],
                  [
                    "TOP_SECRET",
                  ],
                ],
                "type": "propertyMarkings",
              },
            ],
            "office": [
              {
                "type": "unsupportedPolicy",
              },
            ],
            "startDate": [
              {
                "conjunctive": [
                  "CONFIDENTIAL",
                  "INTERNAL",
                ],
                "containerConjunctive": undefined,
                "containerDisjunctive": undefined,
                "disjunctive": [
                  [
                    "SECRET",
                  ],
                  [
                    "TOP_SECRET",
                  ],
                ],
                "type": "propertyMarkings",
              },
            ],
          },
          "$title": "Bruce Banner",
          "class": "Red",
          "employeeId": 20003,
          "favoriteRestaurants": [
            "Pasta Place",
            "Sushi Spot",
          ],
          "fullName": "Bruce Banner",
          "office": "NYC",
          "startDate": "2003-01-01",
        }
      `);
    });
  });
});
export async function shouldError(client) {
  // @ts-expect-error
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldError2(client) {
  // @ts-expect-error
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldCompile_client_fetchOne_old_select(client) {
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldCompile_unstableClient_fetchOne_old_select(client) {
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldCompile_client_fetchOne_new_select(client) {
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldCompile_unstableClient_fetchOne_new_select(client) {
  return client(Employee).fetchOne(1, {
    $select: ["employeeId"]
  });
}
export async function shouldCompile_client_fetchOne_old_noArgs(client) {
  return client(Employee).fetchOne(1);
}
export async function shouldCompile_unstableClient_fetchOne_noArgs(client) {
  return client(Employee).fetchOne(1);
}
//# sourceMappingURL=object.test.js.map