import { CipherType } from "../../vault/enums";
import { CipherView } from "../../vault/models/view/cipher.view";

import { CipherExport } from "./cipher.export";
import { SecureNoteExport } from "./secure-note.export";
import { SshKeyExport } from "./ssh-key.export";

describe("Cipher Export", () => {
  describe("toView", () => {
    it("should preserve existing date values when request dates are undefined", () => {
      const existingView = new CipherView();
      existingView.creationDate = new Date("2023-01-01T00:00:00Z");
      existingView.revisionDate = new Date("2023-01-02T00:00:00Z");
      existingView.deletedDate = new Date("2023-01-03T00:00:00Z");

      const request = CipherExport.template();
      request.type = CipherType.SecureNote;
      request.secureNote = SecureNoteExport.template();
      request.creationDate = undefined;
      request.revisionDate = undefined;
      request.deletedDate = undefined;

      const resultView = CipherExport.toView(request, existingView);
      expect(resultView.creationDate).toEqual(existingView.creationDate);
      expect(resultView.revisionDate).toEqual(existingView.revisionDate);
      expect(resultView.deletedDate).toEqual(existingView.deletedDate);
    });

    it("should set date values when request dates are provided", () => {
      const request = CipherExport.template();
      request.type = CipherType.SecureNote;
      request.secureNote = SecureNoteExport.template();
      request.creationDate = new Date("2023-01-01T00:00:00Z");
      request.revisionDate = new Date("2023-01-02T00:00:00Z");
      request.deletedDate = new Date("2023-01-03T00:00:00Z");

      const resultView = CipherExport.toView(request);
      expect(resultView.creationDate).toEqual(request.creationDate);
      expect(resultView.revisionDate).toEqual(request.revisionDate);
      expect(resultView.deletedDate).toEqual(request.deletedDate);
    });
  });

  describe("SshKeyExport.toView", () => {
    const validSshKey = {
      privateKey: "PRIVATE_KEY",
      publicKey: "PUBLIC_KEY",
      keyFingerprint: "FINGERPRINT",
    };

    it.each([null, undefined, "", "   "])("should throw when privateKey is %p", (value) => {
      const sshKey = { ...validSshKey, privateKey: value } as any;
      expect(() => SshKeyExport.toView(sshKey)).toThrow("SSH key private key is required.");
    });

    it.each([null, undefined, "", "   "])("should throw when publicKey is %p", (value) => {
      const sshKey = { ...validSshKey, publicKey: value } as any;
      expect(() => SshKeyExport.toView(sshKey)).toThrow("SSH key public key is required.");
    });

    it.each([null, undefined, "", "   "])("should throw when keyFingerprint is %p", (value) => {
      const sshKey = { ...validSshKey, keyFingerprint: value } as any;
      expect(() => SshKeyExport.toView(sshKey)).toThrow("SSH key fingerprint is required.");
    });

    it.each([null, undefined, ""])(
      "should not throw for a missing publicKey when derived keys are allowed (value %p)",
      (value) => {
        const sshKey = { ...validSshKey, publicKey: value } as any;
        expect(() => SshKeyExport.toView(sshKey, undefined, true)).not.toThrow();
      },
    );

    it.each([null, undefined, ""])(
      "should not throw for a missing keyFingerprint when derived keys are allowed (value %p)",
      (value) => {
        const sshKey = { ...validSshKey, keyFingerprint: value } as any;
        expect(() => SshKeyExport.toView(sshKey, undefined, true)).not.toThrow();
      },
    );

    it("should succeed with valid inputs", () => {
      const sshKey = { ...validSshKey };
      const result = SshKeyExport.toView(sshKey);
      expect(result).toBeDefined();
      expect(result?.privateKey).toBe(validSshKey.privateKey);
      expect(result?.publicKey).toBe(validSshKey.publicKey);
      expect(result?.keyFingerprint).toBe(validSshKey.keyFingerprint);
    });
  });
});
