import { CliTerseError } from '@alwaysai/alwayscli';
import { Choice } from 'prompts';
import { NOT_IN_ORG_ERROR_MESSAGE } from '../../../constants';
import { AppJsonFile } from '../../../core/app';
import { CliAuthenticationClient } from '../../../infrastructure/authentication-client';
import {
  createAnalyticsPipeline,
  fetchAnalyticsPipelinesForOrg,
  PipelineChannel
} from '../../../infrastructure/rest-client';
import { printAnalytics } from '../../../subcommands/app/analytics/publish';
import { logger, promptForInput, stringifyError } from '../../../util';

function getValidPipelinesFromInput(
  inputPipelines: string[],
  orgPipelines: PipelineChannel[]
): string[] {
  const validUUIDs = orgPipelines.map((pipeline) => pipeline.uuid);
  return inputPipelines.filter((pipeline) => validUUIDs.includes(pipeline));
}

async function promptForPipelineSelection(
  currentPipelines: string[],
  channelIds: PipelineChannel[],
  idTokenAuthorizationHeader: Record<string, string>
): Promise<string[]> {
  const choices: Choice[] = channelIds.map((stream) => ({
    title: stream.name,
    value: stream.uuid,
    selected: currentPipelines.includes(stream.uuid)
  }));

  choices.push({
    title: 'Create A New Pipeline',
    value: 'CREATE_NEW_PIPELINE'
  });

  const selected = await promptForInput({
    purpose: 'choose which pipelines to set',
    questions: [
      {
        type: 'multiselect',
        name: 'pipelines',
        instructions: false,
        message: 'Select pipelines [space to (un)select, enter to confirm]',
        choices
      }
    ]
  });

  const finalPipelines: string[] = [];
  for (const pipelineId of selected.pipelines) {
    if (pipelineId === 'CREATE_NEW_PIPELINE') {
      const { name: pipelineName } = await promptForInput({
        purpose: 'choose a name for the new pipeline',
        questions: [
          {
            type: 'text',
            name: 'name',
            message: 'Name: '
          }
        ]
      });
      const newPipeline = await createAnalyticsPipeline(
        pipelineName,
        idTokenAuthorizationHeader
      );
      finalPipelines.push(newPipeline.uuid);
    } else {
      finalPipelines.push(pipelineId);
    }
  }

  return finalPipelines;
}

export const setAnalyticsPipelinesComponent = async ({
  yes,
  inputs
}: {
  yes: boolean;
  inputs?: string[];
}) => {
  const { getIdAuthorizationHeader } = CliAuthenticationClient();
  const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
  const appCfgFile = AppJsonFile();

  let orgPipelines;
  try {
    orgPipelines = await fetchAnalyticsPipelinesForOrg(
      idTokenAuthorizationHeader
    );
  } catch (error) {
    logger.error(stringifyError(error));
    throw new CliTerseError(NOT_IN_ORG_ERROR_MESSAGE);
  }

  const finalPipelines = yes
    ? getValidPipelinesFromInput(inputs || [], orgPipelines)
    : await promptForPipelineSelection(
        appCfgFile.read().analytics?.pipelines ?? [],
        orgPipelines,
        idTokenAuthorizationHeader
      );

  const result = appCfgFile.update((appCfg) => {
    appCfg.analytics = { ...appCfg.analytics, pipelines: finalPipelines };
  });

  printAnalytics({
    changed: result.changed,
    analytics: appCfgFile.read().analytics
  });
};
