<script>
import { GlAlert, GlButton, GlForm, GlFormGroup, GlFormTextarea } from '@gitlab/ui';
import RefSelector from '~/ref/components/ref_selector.vue';
import { __, s__, sprintf } from '~/locale';
import createCommitMutation from '../queries/create_commit.graphql';
import getFileMetaDataQuery from '../queries/get_file_meta.graphql';
import StepNav from './step_nav.vue';

export const i18n = {
  updateFileHeading: s__('PipelineWizard|Commit changes to your file'),
  createFileHeading: s__('PipelineWizard|Commit your new file'),
  fieldRequiredFeedback: __('This field is required'),
  commitMessageLabel: s__('PipelineWizard|Commit Message'),
  branchSelectorLabel: s__('PipelineWizard|Commit file to Branch'),
  defaultUpdateCommitMessage: s__('PipelineWizardDefaultCommitMessage|Update %{filename}'),
  defaultCreateCommitMessage: s__('PipelineWizardDefaultCommitMessage|Add %{filename}'),
  commitButtonLabel: s__('PipelineWizard|Commit'),
  commitSuccessMessage: s__('PipelineWizard|The file has been committed.'),
  errors: {
    loadError: s__(
      'PipelineWizard|There was a problem while checking whether your file already exists in the specified branch.',
    ),
    commitError: s__('PipelineWizard|There was a problem committing the changes.'),
  },
};

const COMMIT_ACTION = {
  CREATE: 'CREATE',
  UPDATE: 'UPDATE',
};

export default {
  i18n,
  name: 'PipelineWizardCommitStep',
  components: {
    RefSelector,
    GlAlert,
    GlButton,
    GlForm,
    GlFormGroup,
    GlFormTextarea,
    StepNav,
  },
  props: {
    prev: {
      type: Object,
      required: false,
      default: null,
    },
    projectPath: {
      type: String,
      required: true,
    },
    defaultBranch: {
      type: String,
      required: true,
    },
    fileContent: {
      type: String,
      required: false,
      default: '',
    },
    filename: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      branch: this.defaultBranch,
      loading: false,
      loadError: null,
      commitError: null,
      message: null,
    };
  },
  computed: {
    fileExistsInRepo() {
      return this.project?.repository?.blobs.nodes.length > 0;
    },
    commitAction() {
      return this.fileExistsInRepo ? COMMIT_ACTION.UPDATE : COMMIT_ACTION.CREATE;
    },
    defaultMessage() {
      return sprintf(
        this.fileExistsInRepo
          ? this.$options.i18n.defaultUpdateCommitMessage
          : this.$options.i18n.defaultCreateCommitMessage,
        { filename: this.filename },
      );
    },
    isCommitButtonEnabled() {
      return this.fileExistsCheckInProgress;
    },
    fileExistsCheckInProgress() {
      return this.$apollo.queries.project.loading;
    },
    mutationPayload() {
      return {
        mutation: createCommitMutation,
        variables: {
          input: {
            projectPath: this.projectPath,
            branch: this.branch,
            message: this.message || this.defaultMessage,
            actions: [
              {
                action: this.commitAction,
                filePath: `/${this.filename}`,
                content: this.fileContent,
              },
            ],
          },
        },
      };
    },
  },
  apollo: {
    project: {
      query: getFileMetaDataQuery,
      variables() {
        this.loadError = null;
        return {
          fullPath: this.projectPath,
          filePath: this.filename,
          ref: this.branch,
        };
      },
      error() {
        this.loadError = this.$options.i18n.errors.loadError;
      },
    },
  },
  methods: {
    async commit() {
      this.loading = true;
      try {
        const { data } = await this.$apollo.mutate(this.mutationPayload);
        const hasError = Boolean(data.commitCreate.errors?.length);
        if (hasError) {
          this.commitError = this.$options.i18n.errors.commitError;
        } else {
          this.handleCommitSuccess();
        }
      } catch (e) {
        this.commitError = this.$options.i18n.errors.commitError;
      } finally {
        this.loading = false;
      }
    },
    handleCommitSuccess() {
      this.$toast.show(this.$options.i18n.commitSuccessMessage);
      this.$emit('done');
    },
  },
};
</script>

<template>
  <div>
    <h4 v-if="fileExistsInRepo" key="create-heading">
      {{ $options.i18n.updateFileHeading }}
    </h4>
    <h4 v-else key="update-heading">
      {{ $options.i18n.createFileHeading }}
    </h4>
    <gl-alert
      v-if="!!loadError"
      :dismissible="false"
      class="gl-mb-5"
      data-testid="load-error"
      variant="danger"
    >
      {{ loadError }}
    </gl-alert>
    <gl-form class="gl-max-w-48">
      <gl-form-group
        :invalid-feedback="$options.i18n.fieldRequiredFeedback"
        :label="$options.i18n.commitMessageLabel"
        data-testid="commit_message_group"
        label-for="commit_message"
      >
        <gl-form-textarea
          id="commit_message"
          v-model="message"
          :placeholder="defaultMessage"
          data-testid="commit_message"
          size="md"
          @input="(v) => $emit('update:message', v)"
        />
      </gl-form-group>
      <gl-form-group
        :invalid-feedback="$options.i18n.fieldRequiredFeedback"
        :label="$options.i18n.branchSelectorLabel"
        data-testid="branch_selector_group"
        label-for="branch"
      >
        <ref-selector id="branch" v-model="branch" :project-id="projectPath" data-testid="branch" />
      </gl-form-group>
      <gl-alert
        v-if="!!commitError"
        :dismissible="false"
        class="gl-mb-5"
        data-testid="commit-error"
        variant="danger"
      >
        {{ commitError }}
      </gl-alert>
      <step-nav show-back-button v-bind="$props" @back="$emit('back')">
        <template #after>
          <gl-button
            :disabled="isCommitButtonEnabled"
            :loading="fileExistsCheckInProgress || loading"
            category="primary"
            variant="confirm"
            @click="commit"
          >
            {{ $options.i18n.commitButtonLabel }}
          </gl-button>
        </template>
      </step-nav>
    </gl-form>
  </div>
</template>
