import {BrandingApi,ContactsApi,CustomFieldApi,DocumentApi,TemplateApi,SenderIdentitiesApi,TeamsApi,UserApi} from '../../api';
import {ContactDetails,BrandCustomFieldDetails,CustomFormField,DocumentSigner,FormField,Rectangle,SendForSign,AuthenticationSettings,CreateTemplateRequest,TemplateRole,Role,SendForSignFromTemplateForm,ReminderSettings,CreateSenderIdentityRequest,CreateTeamRequest,CreateUser} from '../../model';
import config from '../config';
import * as fs from 'fs';
import { performance } from 'perf_hooks';

describe('Full Integration & Performance Test Suite', () => {
  let senderIdentitiesApi:SenderIdentitiesApi;
  let brandingApi: BrandingApi;
  let contactsApi: ContactsApi;
  let customFieldApi: CustomFieldApi;
  let documentApi: DocumentApi;
  let templateApi: TemplateApi;
  let teamsApi: TeamsApi;
  let userApi:UserApi;

  let brandId;
  let createdUserId;
  let teamName;
  let createdCustomFieldId;
  let createdSenderIdentityId;
  let createdDocumentId;
  let createdTemplateId;
  let emailId;
  let customFieldName;

  const generateRandomEmail = () => `sdktesting${Math.floor(1000 + Math.random() * 9000)}@syncfusion.com`;
  const generateRandomNumber = () => Math.floor(1000 + Math.random() * 9000).toString();

  beforeAll(() => {
    const apiKey = config.apiKey;
    const baseUrl = config.baseUrl;

    if (!apiKey || !baseUrl) {
      throw new Error("Environment variables 'API_KEY' or 'HOST_URL' are not set.");
    }

    brandingApi = new BrandingApi(baseUrl);
    brandingApi.setApiKey(apiKey);

    contactsApi = new ContactsApi(baseUrl);
    contactsApi.setApiKey(apiKey);

    customFieldApi = new CustomFieldApi(baseUrl);
    customFieldApi.setApiKey(apiKey);

    documentApi = new DocumentApi(baseUrl);
    documentApi.setApiKey(apiKey);

    templateApi = new TemplateApi(baseUrl);
    templateApi.setApiKey(apiKey);

    senderIdentitiesApi =new SenderIdentitiesApi(baseUrl);
    senderIdentitiesApi.setApiKey(apiKey);

    teamsApi = new TeamsApi(baseUrl);
    teamsApi.setApiKey(apiKey);

    userApi = new UserApi(baseUrl);
    userApi.setApiKey(apiKey);

    emailId = generateRandomEmail();
    customFieldName = `Test Custom Field ${generateRandomNumber()}`;
    teamName = `sdktestingteam${generateRandomNumber()}`;
  });

  test('Performance Test 1: Create a brand', async () => {
    const brandLogo = fs.createReadStream("tests/documents/logo.jpg");

    const start = performance.now();
    try {
      const response = await brandingApi.createBrand(
        "NodeSDK_Perf",
        brandLogo,
        "Blue",
        "Black",
        "White",
        "{SenderName} from Syncfusion"
      );
      const end = performance.now();
      const duration = end - start;

      console.log(`Brand creation took ${duration.toFixed(10)} ms`);
      brandId = response.brandId;

      expect(brandId).toBeDefined();
      expect(duration).toBeLessThan(10000);
    } catch (error: any) {
      console.error("Error during brand creation:", error.message);
      expect(error).toBeUndefined();
    }
  }, 20000);

  test('Performance Test 2: Create a contact', async () => {
    const contactDetails = new ContactDetails();
    contactDetails.name = "sdktesting";
    contactDetails.email = emailId;

    const start = performance.now();
    try {
      const response = await contactsApi.createContact([contactDetails]);
      const end = performance.now();
      const duration = end - start;

      console.log(`Contact creationcontac took ${duration.toFixed(10)} ms`);

      expect(response).toBeDefined();
      expect(duration).toBeLessThan(10000);
    } catch (error) {
      console.error("Error during contact creation:", error);
      expect(error).toBeUndefined();
    }
  }, 20000);

  test('Performance Test 3: Create a custom field', async () => {
    const formField = new CustomFormField();
    formField.fieldType = CustomFormField.FieldTypeEnum.Signature;
    formField.placeHolder = "string";
    formField.isRequired = true;

    const customFieldDetails = new BrandCustomFieldDetails();
    customFieldDetails.fieldName = customFieldName;
    customFieldDetails.fieldDescription = "string";
    customFieldDetails.fieldOrder = 2;
    customFieldDetails.brandId = brandId;
    customFieldDetails.sharedField = true;
    customFieldDetails.formField = formField;

    const start = performance.now();
    try {
      const response = await customFieldApi.createCustomField(customFieldDetails);
      const end = performance.now();
      const duration = end - start;

      console.log(`Custom field creation took ${duration.toFixed(10)} ms`);
      createdCustomFieldId = response.customFieldId;

      expect(createdCustomFieldId).toBeDefined();
      expect(duration).toBeLessThan(10000);
    } catch (error: any) {
      console.error("Error during custom field creation:", error.message);
      expect(error).toBeUndefined();
    }
  }, 20000);

  test('Performance Test 4: Send document for signing', async () => {
    const signer = new DocumentSigner();
    signer.name = 'Test Signer';
    signer.emailAddress = 'mohammedmushraf.abuthakir+6@syncfusion.com';
    signer.signerOrder = 1;
    signer.signerType = DocumentSigner.SignerTypeEnum.Signer;
    signer.authenticationType = DocumentSigner.AuthenticationTypeEnum.AccessCode;
    signer.authenticationCode = '123456';
    signer.authenticationSettings = {
      authenticationFrequency: AuthenticationSettings.AuthenticationFrequencyEnum.EveryAccess
    };

    const formField = new FormField();
    formField.name = 'Sign';
    formField.fieldType = FormField.FieldTypeEnum.Signature;
    formField.font = FormField.FontEnum.Helvetica;
    formField.pageNumber = 1;
    formField.isRequired = true;
    formField.bounds = new Rectangle();

    signer.formFields = [formField];
    signer.privateMessage = 'This is a private message for signer';

    const sendRequest = new SendForSign();
    sendRequest.title = 'Document SDK API';
    sendRequest.files = [fs.createReadStream('tests/documents/agreement.pdf')];
    sendRequest.enablePrintAndSign = true;
    sendRequest.signers = [signer];
    sendRequest.message = 'Please sign this document';

    const start = performance.now();
    try {
      const response = await documentApi.sendDocument(sendRequest);
      const end = performance.now();
      const duration = end - start;

      console.log(`Document sending took ${duration.toFixed(10)} ms`);
      createdDocumentId = response.documentId;

      expect(createdDocumentId).toBeDefined();
      expect(duration).toBeLessThan(10000);
    } catch (error) {
      console.error("Error during document sending:", error);
      expect(error).toBeUndefined();
    }
  }, 20000);

  test('Performance Test 5: Create a template', async () => {
    const signatureField = new FormField();
    signatureField.fieldType = FormField.FieldTypeEnum.Signature;
    signatureField.pageNumber = 1;
    const bounds = new Rectangle();
    bounds.x = 50;
    bounds.y = 100;
    bounds.width = 150;
    bounds.height = 50;
    signatureField.bounds = bounds;

    const role = new TemplateRole();
    role.index = 1;
    role.name = "Signer";
    role.defaultSignerName = "John Doe";
    role.defaultSignerEmail = "johndoe@example.com";
    role.signerOrder = 1;
    role.signerType = TemplateRole.SignerTypeEnum.Signer;
    role.formFields = [signatureField];

    const createTemplateRequest = new CreateTemplateRequest();
    createTemplateRequest.title = "Testing node sdk";
    createTemplateRequest.description = "Testing integration test case";
    createTemplateRequest.documentTitle = "Node sdk test case";
    createTemplateRequest.documentMessage = "Please check and sign";
    createTemplateRequest.roles = [role];
    createTemplateRequest.enableReassign = true;
    createTemplateRequest.enableSigningOrder = true;
    createTemplateRequest.allowNewRoles = true;
    createTemplateRequest.allowMessageEditing = true;
    createTemplateRequest.allowNewFiles = true;
    createTemplateRequest.files = [fs.createReadStream("tests/documents/agreement.pdf")];

    const start = performance.now();
    try {
      const response = await templateApi.createTemplate(createTemplateRequest);
      const end = performance.now();
      const duration = end - start;

      console.log(`Template creation took ${duration.toFixed(10)} ms`);
      createdTemplateId = response.templateId;

      expect(createdTemplateId).toBeDefined();
      expect(duration).toBeLessThan(10000);
    } catch (error: any) {
      console.error("Error during template creation:", error.message);
      expect(error).toBeUndefined();
    }
  }, 20000);

test('Performanc Test 6: should send document for signing using template', async () => {
    const start = performance.now();
    const formField = new FormField();
    formField.fieldType = FormField.FieldTypeEnum.Signature;
    formField.pageNumber = 1;
    const bounds = new Rectangle();
    bounds.x = 100;
    bounds.y = 50;
    bounds.width = 100;
    bounds.height = 100;
    formField.bounds = bounds;
    const role = new Role();
    role.roleIndex = 50;
    role.signerName = "Divya";
    role.signerEmail = "divya.boopathy+20@syncfusion.com";
    role.signerOrder = 1;
    role.enableEmailOTP = false;
    role.signerType = Role.SignerTypeEnum.Signer;
    role.authenticationType = Role.AuthenticationTypeEnum.AccessCode;
    role.authenticationCode = '123456';
    role.authenticationSettings = {
            authenticationFrequency: AuthenticationSettings.AuthenticationFrequencyEnum.EveryAccess
        };
    role.signerRole = "Manager";
    role.privateMessage = "Please check and sign the document";
    role.formFields = [formField];
    const sendForSignFromTemplate = new SendForSignFromTemplateForm();
    const files = fs.createReadStream("tests/documents/agreement.pdf");
    sendForSignFromTemplate.files = [files];
    sendForSignFromTemplate.title = "Invitation form";
    sendForSignFromTemplate.message = "Kindly review and sign this.";
    sendForSignFromTemplate.roles = [role];
    sendForSignFromTemplate.disableEmails = false;
    sendForSignFromTemplate.disableSMS = false;
    sendForSignFromTemplate.hideDocumentId = true;
    sendForSignFromTemplate.labels = ["Invitation", "Form", "Test"];
    const reminderSettings = new ReminderSettings();
    reminderSettings.reminderDays = 3;
    reminderSettings.reminderCount = 5;
    reminderSettings.enableAutoReminder = false;
    sendForSignFromTemplate.reminderSettings = reminderSettings;
    sendForSignFromTemplate.expiryValue = 60;
    sendForSignFromTemplate.disableExpiryAlert = true;
    sendForSignFromTemplate.enablePrintAndSign = true;
    sendForSignFromTemplate.enableReassign = true;
    sendForSignFromTemplate.enableSigningOrder = true;
    try {
      const response = await templateApi.sendUsingTemplate(createdTemplateId, sendForSignFromTemplate);
      const end = performance.now();
      const duration = end - start;
      console.log(`Send document from template took ${duration.toFixed(10)} ms`);
      expect(duration).toBeLessThan(10000);
      console.log("Document sent for signing using template successfully:", response);
      expect(response).toBeDefined();
    } catch (error:any) {
      console.error("Error occurred while calling the API:", error.message);
      expect(error.message).toBeUndefined();
    }
  }, 20000);

  test('Performance Test 7: should create sender identity successfully', async () => {
      const start = performance.now();
      const createSenderIdentityRequest = new CreateSenderIdentityRequest();
      createSenderIdentityRequest.name = "SenderIdentity API";
      createSenderIdentityRequest.email = emailId;
      createSenderIdentityRequest.redirectUrl = "https://boldsign.com";
      try {
        const response = await senderIdentitiesApi.createSenderIdentities(createSenderIdentityRequest);
        console.log("Sender Identity created successfully:", response);
        createdSenderIdentityId = response;
        console.log("Created Sender Identity ID:", createdSenderIdentityId);
        const end = performance.now();
        const duration = end - start;
        console.log(`Sender Identity creation took ${duration.toFixed(10)} ms`);
        expect(duration).toBeLessThan(10000);
        expect(response).toBeDefined();
      } catch (error:any) {
        console.log("Error occurred while calling the API:", error.message);
        expect(error.message).toBeUndefined();
      }
    },20000);

  test('Performance test 8: should create team successfully', async () => {
      const start = performance.now();
      const createTeamRequest = new CreateTeamRequest();
      createTeamRequest.teamName = teamName;
      try {
          const createTeamResponse = await teamsApi.createTeam(createTeamRequest);
          console.log('Team created successfully:', createTeamResponse);
          const end = performance.now();
          const duration = end - start;
          console.log(`Teams creation took ${duration.toFixed(10)} ms`);
          expect(duration).toBeLessThan(10000);
          expect(createTeamResponse).toBeDefined();
      } catch (error:any) {
          console.error('Error occurred while creating team:', error.message);
          expect(error.message).toBeUndefined();
      }
  },20000);

  test('Performance test 9:should create user successfully', async () => {
      const start = performance.now();
      const createUserRequest = new CreateUser();
      createUserRequest.emailId = emailId;
      createUserRequest.userRole = CreateUser.UserRoleEnum.Member;
      try {
          const response = await userApi.createUser([createUserRequest]);
          console.log("User created successfully:", response);
          console.log("Created User ID:", createdUserId);
          const end = performance.now();
          const duration = end - start;
          console.log(`User creation took ${duration.toFixed(10)} ms`);
          expect(duration).toBeLessThan(10000);
          expect(response).toBeDefined();
        } catch (error:any) {
          console.error("Error occurred while calling the API:", error.message);
          expect(error.message).toBeUndefined();
        }
    },20000);
});