import axios, { AxiosError } from 'axios';
import path from 'path';

import fsp from 'fs/promises';
import { randomBytes } from 'crypto';
import { ComponentSetWebModelForCreate, Manifest, ManifestServiceForDev } from '@squiz/component-lib';
import { parseEnvVarForVar } from '@squiz/dx-common-lib';
import { ContentApi } from '@squiz/component-web-api-lib';
import { config } from 'dotenv';
import { execSync } from 'child_process';
import { getLogger } from '@squiz/dx-logger-lib';
import { uploadComponentFolder } from '../upload-component-folder';
import { buildDevelopmentJwt, DxpServiceId } from '@squiz/dxp-auth-lib';

config();

interface Config {
  managementServiceUrl: string;
  renderServiceUrl: string;
  pageRenderServiceUrl: string;
  contentServiceUrl: string;
  tenantId: string;
  jobServiceUrl: string;
  ci_buildVersion: string;
  ci_buildBranch: string;
}

const configObj: Config = {
  managementServiceUrl: parseEnvVarForVar('COMPONENT_MANAGEMENT_SERVICE_URL').replace(/\/+$/, ''),
  pageRenderServiceUrl: parseEnvVarForVar('PAGE_RENDER_SERVICE_URL').replace(/\/+$/, ''),
  renderServiceUrl: parseEnvVarForVar('COMPONENT_RENDER_SERVICE_URL').replace(/\/+$/, ''),
  contentServiceUrl: parseEnvVarForVar('CONTENT_API_URL').replace(/\/+$/, ''),
  tenantId: parseEnvVarForVar('TENANT_ID'),
  jobServiceUrl: parseEnvVarForVar('JOB_SERVICE_URL').replace(/\/+$/, ''),
  ci_buildVersion: parseEnvVarForVar('CI_COMMIT_SHORT_SHA'),
  ci_buildBranch: parseEnvVarForVar('CI_COMMIT_REF_NAME'),
};

if (!configObj.ci_buildVersion) {
  configObj.ci_buildVersion = execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim();
}

if (!configObj.ci_buildBranch) {
  configObj.ci_buildBranch = execSync('git branch --show-current', { encoding: 'utf-8' }).trim();
}

export default configObj;

const authToken =
  'Bearer ' +
  buildDevelopmentJwt({
    service: {
      [DxpServiceId.contentStore]: {
        privileges: [
          'CONTENT_SCHEMA_READ',
          'CONTENT_SCHEMA_WRITE',
          'CONTENT_ITEM_READ',
          'CONTENT_ITEM_WRITE',
          'SETTINGS_READ',
          'SETTINGS_WRITE',
          'PAGE_CONTENTS_WRITE',
          'PAGE_CONTENTS_READ',
        ],
      },
      [DxpServiceId.components]: {
        privileges: [
          'COMPONENT_READ',
          'COMPONENT_WRITE',
          'COMPONENT_DEPLOY',
          'COMPONENT_SET_WRITE',
          'COMPONENT_DELETE',
          'COMPONENT_SET_WRITE',
          'COMPONENT_SET_READ',
          'COMPONENT_SET_ENVIRONMENT_READ',
          'COMPONENT_SET_ENVIRONMENT_WRITE',
        ],
      },
      [DxpServiceId.segmentation]: {
        privileges: ['SEGMENT_READ'],
      },
    },
  });

export const managementService = axios.create({
  baseURL: configObj.managementServiceUrl + '/v1',
  headers: {
    Authorization: authToken,
  },
});

export const managementServiceRoot = axios.create({
  baseURL: configObj.managementServiceUrl,
  headers: {
    Authorization: authToken,
  },
});

export const renderService = axios.create({
  baseURL: configObj.renderServiceUrl,
});

export const contentService = axios.create({
  baseURL: configObj.contentServiceUrl,
  headers: {
    Authorization: authToken,
  },
});

export const pageRenderService = axios.create({
  baseURL: configObj.pageRenderServiceUrl,
});

export const jobService = axios.create({
  baseURL: configObj.jobServiceUrl,
  headers: {
    Authorization: authToken,
  },
});

export const ci_buildVersion = configObj.ci_buildVersion;
export const ci_buildBranch = configObj.ci_buildBranch;

export async function getTestComponents() {
  const componentsDir = path.join(__dirname, '/__components__/');
  const manifestService = new ManifestServiceForDev(componentsDir, getLogger({ name: 'getTestComponents' }));
  return await manifestService.listAllComponentManifests();
}

export async function getTestComponent(componentFolderName: string) {
  const componentsDir = path.join(__dirname, '/__components__/', componentFolderName);
  const manifestService = new ManifestServiceForDev(componentsDir, getLogger({ name: 'getTestComponents' }));
  return await manifestService.listAllComponentManifests();
}

export async function getTestJobs() {
  const jobsDir = path.join(__dirname, '/__jobs__/');
  const manifestService = new ManifestServiceForDev(jobsDir, getLogger({ name: 'getTestJobs' }));
  return await manifestService.listAllComponentManifests();
}

export async function createFile(filePath: string, sizeInMB: number) {
  const content = randomBytes(sizeInMB * 1000000);
  await fsp.writeFile(`${filePath}`, content);
}

export function removeFile(filePath: string) {
  fsp.unlink(filePath);
}

export async function deleteComponentSet(webPath: string) {
  try {
    await managementService.delete(`/component-set/${webPath}`);
  } catch (error) {
    // no ops
  }
}

export async function addComponentSet(componentSet: ComponentSetWebModelForCreate) {
  try {
    await managementService.post(`/component-set`, componentSet);
  } catch (error) {
    //no ops
  }
}

export async function addContentItem(contentItem: ContentApi.ContentItemWebModel) {
  try {
    await contentService.post(`/content-item`, contentItem);
  } catch (error) {
    //no ops
  }
}

export async function deleteContentItem(contentItemId: string) {
  try {
    await contentService.delete(`/content-item/${contentItemId}`);
  } catch (error) {
    //no ops
  }
}

export async function deleteContentSchema(contentSchemaName: string) {
  try {
    await contentService.delete(`/content-item/${contentSchemaName}`);
  } catch (error) {
    //no ops
  }
}

export async function deleteComponent(manifest: Manifest) {
  try {
    await managementService.delete(`/component/${manifest.getName()}`);
    await contentService.delete(
      `/content-schema/${manifest.getName()}/${manifest.getVersion()}/${manifest.getComponentFunctionByName().name}`,
    );
  } catch (error) {
    if ((error as AxiosError).response?.status !== 404) {
      throw error;
    }
  }
}

export async function deleteComponents(manifests: Manifest[]) {
  await Promise.all(manifests.map((manifest) => deleteComponent(manifest)));
}

export async function uploadTestComponent(componentFolderPath: string, tempFolderPath: string): Promise<void> {
  const componentPath = path.join(__dirname, componentFolderPath);
  await uploadComponentFolder(managementServiceRoot, configObj.managementServiceUrl, componentPath, tempFolderPath);
}

export async function deleteJob(manifest: Manifest) {
  try {
    await jobService.delete(`/job/${manifest.getName()}/${manifest.getVersion()}`);
  } catch (error) {
    if ((error as AxiosError).response?.status === 404) {
      const logger = getLogger({ name: 'delete job' });
      logger.info('job not found');
    } else {
      throw error;
    }
  }
}

export async function deleteJobs(manifests: Manifest[]) {
  await Promise.all(manifests.map((manifest) => deleteJob(manifest)));
}
