<script setup>

import { ref, useTemplateRef, computed, onMounted } from 'vue';
import { Button, Dialog, FormGroup, SingleSelect, TextInput, NumberInput, Checkbox, MaskedInput } from '@cloudron/pankow';
import SettingsItem from './SettingsItem.vue';
import MailModel from '../models/MailModel.js';
import { RELAY_PROVIDERS } from '../constants.js';
import { prettyRelayProviderName } from '../utils';

const props = defineProps({
  domain: { type: String, required: true },
  adminDomain: { type: String, required: true }
});

const mailModel = MailModel.create();

const providerSpfDoc = computed(() => {
  const tmp = RELAY_PROVIDERS.find(p => p.provider === provider.value);
  return (tmp ? tmp.spfDoc : '') || '';
});

const mailConfig = ref({});
const dialog = useTemplateRef('dialog');
const busy = ref(false);
const formError = ref('');
const currentProvider = ref('cloudron-smtp');
const provider = ref('cloudron-smtp');
const host = ref('');
const port = ref(1);
const acceptSelfSignedCerts = ref(false);
const serverApiToken = ref('');
const username = ref('');
const password = ref('');

function usesExternalServer(provider) {
  return provider !== 'cloudron-smtp' && provider !== 'noop';
}

function usesTokenAuth(provider) {
  return provider === 'postmark-smtp' || provider === 'sendgrid-smtp' || provider === 'sparkpost-smtp';
}

function usesPasswordAuth(provider) {
  return provider === 'external-smtp'
    || provider === 'brevo-smtp'
    || provider === 'ses-smtp'
    || provider === 'google-smtp'
    || provider === 'mailgun-smtp'
    || provider === 'elasticemail-smtp'
    || provider === 'office365-legacy-smtp'
    || provider === 'mailjet-smtp';
}

const form = useTemplateRef('form');
const isFormValid = ref(false);
function checkValidity() {
  isFormValid.value = form.value ? form.value.checkValidity() : false;
}

function onProviderChange() {
  // reset the form
  host.value = '';
  port.value = 587;
  acceptSelfSignedCerts.value = false;
  serverApiToken.value = '';
  username.value = '';
  password.value = '';

  // prefill from preset
  const tmp = RELAY_PROVIDERS.find(p => p.provider === provider.value);
  if (!tmp) return;

  if (tmp.host) host.value = tmp.host;
  if (tmp.port) port.value = tmp.port;
  if (tmp.username) username.value = tmp.username;
}

async function onShowDialog() {
  formError.value = '';
  busy.value = false;

  const [error, result] = await mailModel.config(props.domain);
  if (error) return console.error(error);

  mailConfig.value = result;
  provider.value = result.relay.provider;
  host.value = result.relay.host;
  port.value = result.relay.port;
  username.value = result.relay.username;
  password.value = result.relay.password;
  acceptSelfSignedCerts.value = result.relay.acceptSelfSignedCerts;
  serverApiToken.value = result.relay.serverApiToken;

  dialog.value.open();

  setTimeout(checkValidity, 100); // update state of the confirm button
}

async function onSubmit() {
  if (!form.value.reportValidity()) return;

  busy.value = true;
  formError.value = '';

  const data = {
    provider: provider.value,
  };

  if (usesExternalServer(data.provider)) {
    data.username = username.value;
    if (password.value) data.password = password.value;
    data.host = host.value;
    data.port = parseInt(port.value);
    data.acceptSelfSignedCerts = acceptSelfSignedCerts.value;
    data.forceFromAddress = false;
  }

  // fill in provider specific username/password usage
  if (data.provider === 'postmark-smtp') {
    if (serverApiToken.value) data.username = serverApiToken.value;
    if (serverApiToken.value) data.password = serverApiToken.value;
    data.forceFromAddress = true; // postmark requires the "From:" in mail to be a Sender Signature
  } else if (data.provider === 'sendgrid-smtp') {
    data.username = 'apikey';
    if (serverApiToken.value) data.password = serverApiToken.value;
  } else if (data.provider === 'sparkpost-smtp') {
    data.username = 'SMTP_Injection';
    if (serverApiToken.value) data.password = serverApiToken.value;
  }

  const [error] = await mailModel.setMailRelay(props.domain, data);
  if (error) {
    formError.value = error.body ? error.body.message : 'Internal error';
    busy.value = false;
    return console.error(error);
  }

  currentProvider.value = provider.value;

  dialog.value.close();

  busy.value = false;
}

onMounted(async () => {
  const [error, result] = await mailModel.config(props.domain);
  if (error) return console.error(error);

  provider.value = result.relay.provider;
  currentProvider.value = result.relay.provider;
});

</script>

<template>
  <div>
    <Dialog ref="dialog"
      :title="$t('email.outbound.title')"
      :confirm-label="$t('main.dialog.save')"
      :confirm-busy="busy"
      :reject-label="$t('main.dialog.cancel')"
      :reject-active="!busy && isFormValid"
       reject-style="secondary"
      @confirm="onSubmit()"
    >
      <div>
        <SingleSelect v-model="provider" :options="RELAY_PROVIDERS" option-key="provider" option-label="name" @select="onProviderChange()" style="display: flex;"/>

        <!-- set max-width here until Dialog supports that -->
        <div v-if="providerSpfDoc" class="text-warning" style="margin: 10px 0; max-width: 600px" v-html="$t('email.outbound.mailRelay.spfDocInfo', { name: provider, spfDocsLink: providerSpfDoc })"></div>

        <div class="error-label" style="margin: 10px 0;" v-if="provider === 'noop'">{{ $t(domain === adminDomain ? 'email.outbound.noopAdminDomainWarning' : 'email.outbound.noopNonAdminDomainWarning') }}</div>

        <div class="error-label" v-if="formError">{{ formError }}</div>

        <form ref="form" @submit.prevent="onSubmit()" autocomplete="off" @input="checkValidity()">
          <fieldset :disabled="busy" v-if="usesExternalServer(provider)">
            <input type="submit" style="display: none" :disabled="busy || !isFormValid"/>

            <FormGroup>
              <label for="hostInput">{{ $t('email.outbound.mailRelay.host') }}</label>
              <TextInput id="hostInput" v-model="host" required />
            </FormGroup>

            <FormGroup>
              <label for="portInput">{{ $t('email.outbound.mailRelay.port') }}</label>
              <NumberInput id="portInput" v-model="port" min="1" required />
            </FormGroup>

            <Checkbox v-model="acceptSelfSignedCerts" :label="$t('email.outbound.mailRelay.selfsignedCheckbox')" v-if="provider === 'external-smtp' || provider === 'external-smtp-noauth'"/>

            <!-- Postmark, Sendgrid, SparkPost -->
            <FormGroup v-if="usesTokenAuth(provider)">
              <label for="serverApiTokenInput">{{ $t('email.outbound.mailRelay.apiTokenOrKey') }}</label>
              <MaskedInput id="serverApiTokenInput" v-model="serverApiToken" required />
            </FormGroup>

            <!-- Other -->
            <FormGroup v-if="usesPasswordAuth(provider)">
              <label for="usernameInput">{{ $t('email.outbound.mailRelay.username') }}</label>
              <TextInput id="usernameInput" v-model="username" required />
            </FormGroup>

            <FormGroup v-if="usesPasswordAuth(provider)">
              <label for="passwordInput">{{ $t('email.outbound.mailRelay.password') }}</label>
              <MaskedInput id="passwordInput" v-model="password" required />
            </FormGroup>
          </fieldset>
        </form>

      </div>
    </Dialog>

    <SettingsItem>
      <FormGroup>
        <label>{{ $t('email.outbound.title') }} <sup><a href="https://docs.cloudron.io/email/#relay-outbound-mails" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
        <div>
          <span>{{ prettyRelayProviderName(currentProvider) }}</span> / <span v-html="$t('email.outbound.description')"></span>
        </div>
      </FormGroup>
      <div style="display: flex; align-items: center;">
        <Button tool plain @click="onShowDialog()">{{ $t('main.dialog.edit') }}</Button>
      </div>
    </SettingsItem>
  </div>
</template>
