<script setup>

import { useI18n } from 'vue-i18n';
const i18n = useI18n();
const t = i18n.t;

import { ref, onMounted, useTemplateRef, inject } from 'vue';
import { Button, Checkbox, InputDialog, Dialog, FormGroup, Switch, SingleSelect } from 'pankow';
import { prettyDecimalSize, sleep } from 'pankow/utils';
import Section from '../components/Section.vue';
import SettingsItem from '../components/SettingsItem.vue';
import CatchAllSettingsItem from '../components/CatchAllSettingsItem.vue';
import MailRelaySettingsItem from '../components/MailRelaySettingsItem.vue';
import DashboardModel from '../models/DashboardModel.js';
import DomainsModel from '../models/DomainsModel.js';
import MailModel from '../models/MailModel.js';
import ProfileModel from '../models/ProfileModel.js';

const dashboardModel = DashboardModel.create();
const domainsModel = DomainsModel.create();
const mailModel = MailModel.create();
const profileModel = ProfileModel.create();

const features = inject('features');
const subscriptionRequiredDialog = inject('subscriptionRequiredDialog');

const inputDialog = useTemplateRef('inputDialog');
const enableIncomingDialog = useTemplateRef('enableIncomingDialog');
const connectionDialog = useTemplateRef('connectionDialog');
const domains = ref([]);
const domain = ref('');
const domainProvider = ref('');
const mailConfig = ref({});
const mailFqdn = ref('');
const adminDomain = ref('');
const adminDomainProvider = ref('');
const incomingEnabled = ref(false);
const enableIncomeBusy = ref(false);
const enableIncomingSetupDns = ref(true);
const infoMenu = ref([]);
const busyRefresh = ref(true);
const mailboxCount = ref('');
const inboundEnabled = ref(false);
const outboundEnabled = ref(false);
const usage = ref(0);

async function onSendTestMail() {
  const [error, result] = await profileModel.get();
  if (error) return console.error(error);

  const address = await inputDialog.value.prompt({
    value: result.email,
    title: t('emails.testMailDialog.title', { domain: domain.value }),
    message: t('emails.testMailDialog.description', { domain: domain.value }),
    confirmLabel: t('emails.testMailDialog.sendAction'),
    rejectLabel: t('main.dialog.cancel'),
    rejectStyle: 'secondary'
  });

  if (!address) return;

  const [sendError] = await mailModel.sendTestMail(domain.value, address);
  if (sendError) {
    window.pankow.notify({ text: sendError.body ? sendError.body.message : 'Failed to send mail', type: 'danger' });
    return console.error(sendError);
  }

  window.pankow.notify({ text: 'Mail sent', type: 'success' });
}


function onShowConnectionDialog() {
  connectionDialog.value.open();
}

async function onAskIncomingToggle(value) {
  if (value) {
    enableIncomeBusy.value = false;
    return enableIncomingDialog.value.open();
  }

  const yes = await inputDialog.value.confirm({
    title: t('email.disableEmailDialog.title', { domain: domain.value }),
    message: t('email.disableEmailDialog.description', { domain: domain.value }),
    confirmStyle: 'danger',
    confirmLabel: t('email.disableEmailDialog.disableAction'),
    rejectLabel: t('main.dialog.cancel'),
    rejectStyle: 'secondary',
  });

  // reset switch
  if (!yes) return incomingEnabled.value = true;

  const [error] = await mailModel.setEnabled(domain.value, false);
  if (error) return console.error(error);

  await onDomainChanged();
}

async function onEnableIncoming() {
  enableIncomeBusy.value = true;

  const [error] = await mailModel.setEnabled(domain.value, true);
  if (error) return console.error(error);

  // FIXME this has to be done in the backend here! reconfigureEmailApps();

  if (enableIncomingSetupDns.value) {
    const [error] = await domainsModel.setDnsRecords({ domain: domain.value, type: 'mail' });
    if (error) console.error(error);
  }

  await onDomainChanged();

  enableIncomingDialog.value.close();
  enableIncomeBusy.value = false;
}


const mailFromValidation = ref(false);
const mailFromValidationBusy = ref(false);

async function onToggleMailFromValidation(value) {
  mailFromValidationBusy.value = true;

  const [error] = await mailModel.setMailFromValidation(domain.value, value);
  if (error) {
    mailFromValidation.value = !value;
    mailFromValidationBusy.value = false;
    return console.error(error);
  }

  mailFromValidationBusy.value = false;
}


const signatureDialog = useTemplateRef('signatureDialog');
const signatureBusy = ref(false);
const signatureText = ref('');
const signatureHtml = ref('');

function onShowSignatureDialog() {
  signatureBusy.value = false;
  signatureDialog.value.open();
}

async function onSubmitSignature() {
  signatureBusy.value = true;

  const [error] = await mailModel.setMailBanner(domain.value, signatureText.value, signatureHtml.value);
  if (error) return console.error(error);

  signatureDialog.value.close();
  signatureBusy.value = false;
}

async function onDomainChanged() {
  busyRefresh.value = true;

  let [error, result] = await domainsModel.get(domain.value);
  if (error) return console.error(error);

  domainProvider.value = result.provider;

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

  mailConfig.value = result;
  inboundEnabled.value = result.enabled;
  outboundEnabled.value = result.relay?.provider !== 'noop';
  incomingEnabled.value = result.enabled;
  mailFromValidation.value = result.mailFromValidation;
  signatureText.value = mailConfig.value.banner.text || '';
  signatureHtml.value = mailConfig.value.banner.html || '';

  infoMenu.value = [{
    label: t('app.docsAction'),
    href: 'https://docs.cloudron.io/email/',
    target: '_blank',
  }, {
    label: t('email.config.clientConfiguration'),
    disabled: !mailConfig.value.enabled,
    action: onShowConnectionDialog
  }];

  // do this even if no outbound since people forget to remove mailboxes
  [error, result] = await mailModel.mailboxCount(domain.value);
  if (error) console.error(error);

  mailboxCount.value = result;

  // this may temporarily fail while the mail server is restarting
  while (true) {
    const [error, result] = await mailModel.usage(domain.value);
    if (error && error.status === 424) {
      await sleep(1000);
      continue;
    } else if (error) return console.error(error);

    usage.value = 0;
    // we used to use quotaValue here but it's quite different wrt diskSize. so choose diskSize consistently
    // also, quotaValue can be missing for deleted mailboxes that are on disk but removed from dovecot/ldap itself
    Object.keys(result).forEach(function (m) { usage.value += result[m].diskSize; });

    break;
  }

  busyRefresh.value = false;
}

onMounted(async () => {
  let [error, result] = await dashboardModel.config();
  if (error) return console.error(error);

  mailFqdn.value = result.mailFqdn;
  adminDomain.value = result.adminDomain;

  [error, result] = await domainsModel.get(result.adminDomain);
  if (error) return console.error(error);
  adminDomainProvider.value = result.provider;

  [error, result] = await domainsModel.list();
  if (error) return console.error(error);

  domains.value = result;
  domain.value = domains.value[0].domain;

  await onDomainChanged();
});

</script>

<template>
  <div class="content">
    <InputDialog ref="inputDialog"/>

    <Dialog ref="connectionDialog"
      :title="$t('email.howToConnectInfoModal')"
      :reject-label="$t('main.dialog.close')"
    >
      <div>
        <p v-html="$t('email.incoming.howToConnectDescription', { domain: domain })"></p>

        <p><b>{{ $t('email.incoming.incomingUserInfo') }}</b><br/><i>mailboxname</i>@{{ domain }}</p>
        <p><b>{{ $t('email.incoming.incomingPasswordInfo') }}</b><br/>{{ $t('email.incoming.incomingPasswordUsage') }}</p>
        <p><b>{{ $t('email.incoming.incomingServerInfo') }}</b><br/>{{ $t('email.incoming.server') }}: <span>{{ mailFqdn }}</span><br/>{{ $t('email.incoming.port') }}: 993 (TLS)</p>
        <p><b>{{ $t('email.incoming.outgointServerInfo') }}</b><br/>{{ $t('email.incoming.server') }}: <span>{{ mailFqdn }}</span><br/>{{ $t('email.incoming.port') }}: 587 (STARTTLS) or 465 (TLS)</p>
        <p><b>{{ $t('email.incoming.sieveServerInfo') }}</b><br/>{{ $t('email.incoming.server') }}: <span>{{ mailFqdn }}</span><br/>{{ $t('email.incoming.port') }}: 4190 (STARTTLS)</p>
      </div>
    </Dialog>

    <Dialog ref="enableIncomingDialog"
      :title="$t('email.enableEmailDialog.title', { domain: domain })"
      :confirm-label="$t('email.enableEmailDialog.enableAction')"
      :confirm-busy="enableIncomeBusy"
      :reject-label="enableIncomeBusy ? '' : $t('main.dialog.cancel')"
       reject-style="secondary"
      @confirm="onEnableIncoming()"
      @reject="incomingEnabled = false"
    >
      <div>
        <p v-html="$t('email.enableEmailDialog.description', { domain: domain, requiredPortsDocsLink: 'https://docs.cloudron.io/email/#required-ports' })"></p>
        <p class="text-danger" v-if="adminDomainProvider === 'cloudflare'" v-html="$t('email.enableEmailDialog.cloudflareInfo', { adminDomain, mailFqdn })"></p>
        <div v-if="domainProvider === 'noop' || domainProvider === 'manual'" v-html="$t('email.enableEmailDialog.noProviderInfo')"></div>
        <div v-else>
          <Checkbox v-model="enableIncomingSetupDns" :label="$t('email.enableEmailDialog.setupDnsCheckbox')"/>
          <div v-html="$t('email.enableEmailDialog.setupDnsInfo', { importEmailDocsLink: 'https://docs.cloudron.io/guides/import-email' })"></div>
        </div>
      </div>
    </Dialog>

    <Dialog ref="signatureDialog"
      :title="$t('email.signature.title')"
      :confirm-label="$t('main.dialog.save')"
      :confirm-busy="signatureBusy"
      :reject-label="signatureBusy ? '' : $t('main.dialog.cancel')"
       reject-style="secondary"
      @confirm="onSubmitSignature()"
    >
      <div>
        <form @submit.prevent="onSubmitSignature()" autocomplete="off">
          <fieldset :disabled="signatureBusy">
            <input type="submit" style="display: none"/>

            <FormGroup>
              <label for="sinatureTextInput">{{ $t('email.signature.plainTextFormat') }}</label>
              <textarea id="sinatureTextInput" v-model="signatureText" rows="4"></textarea>
            </FormGroup>

            <FormGroup>
              <label class="sinatureHtmlInput">{{ $t('email.signature.htmlFormat') }}</label>
              <textarea id="sinatureHtmlInput" v-model="signatureHtml" rows="4"></textarea>
            </FormGroup>

          </fieldset>
        </form>
      </div>
    </Dialog>

    <Section :title="$t('email.config.title', { domain: domain })">
      <template #header-buttons>
        <SingleSelect v-if="domains.length" v-model="domain" :options="domains" option-key="domain" option-label="domain" @select="onDomainChanged"/>
        <Button secondary tool icon="fa-solid fa-book" v-tooltip="$t('app.docsActionTooltip')" :menu="infoMenu" />
      </template>

      <div v-if="busyRefresh">{{ $t('main.loadingPlaceholder') }} ...</div>
      <div v-else>
        <div v-if="inboundEnabled">
          {{ $t('emails.domains.stats', { mailboxCount: mailboxCount, usage: prettyDecimalSize(usage) }) }}
        </div>
        <div v-else>
          <span v-if="outboundEnabled">{{ $t('emails.domains.outbound') }}</span>
          <span v-else>{{ $t('emails.domains.disabled') }}</span>
        </div>
      </div>
    </Section>

    <!-- TODO translation -->
    <Section title="Sending" :padding="false" v-if="!busyRefresh">
      <template #header-buttons>
        <Button @click="onSendTestMail">{{ $t('emails.domains.testEmailTooltip') }}</Button>
      </template>

      <MailRelaySettingsItem v-if="domain" :domain="domain"/>

      <SettingsItem>
        <FormGroup>
          <label>{{ $t('email.masquerading.title') }}</label>
          <div v-html="$t('email.masquerading.description')"></div>
        </FormGroup>
        <Switch v-model="mailFromValidation" @change="onToggleMailFromValidation" :disabled="mailFromValidationBusy"/>
      </SettingsItem>

      <SettingsItem>
        <FormGroup>
          <label>{{ $t('email.signature.title') }}</label>
          <div v-html="$t('email.signature.description')"></div>
        </FormGroup>
        <div style="display: flex; align-items: center">
          <Button tool plain @click="onShowSignatureDialog()">{{ $t('main.dialog.edit') }}</Button>
        </div>
      </SettingsItem>
    </Section>

    <!-- TODO translation -->
    <Section title="Receiving" :padding="false" v-if="!busyRefresh" :title-badge="!features.emailServer ? 'Upgrade' : ''">
      <SettingsItem>
        <FormGroup>
          <label>{{ $t('email.incoming.title') }}</label>
          <div>{{ $t(mailConfig.enabled ? 'email.incoming.enabled' : 'email.incoming.disabled') }}</div>
        </FormGroup>
        <Switch v-model="incomingEnabled" :disabled="busyRefresh || !features.emailServer" @change="onAskIncomingToggle"/>
      </SettingsItem>

      <CatchAllSettingsItem :domain-config="mailConfig" :disabled="!features.emailServer"/>
    </Section>
  </div>
</template>
