<script setup>

import { ref, onMounted, useTemplateRef, watchEffect } from 'vue';
import { Button, SingleSelect, FormGroup, TextInput, Notification } from '@cloudron/pankow';
import { copyToClipboard } from '@cloudron/pankow/utils';
import { redirectIfNeeded } from '../utils.js';
import DomainsModel from '../models/DomainsModel.js';
import ProvisionModel from '../models/ProvisionModel.js';
import DomainProviderForm from '../components/DomainProviderForm.vue';
import Whirlpool from '../components/Whirlpool.vue';
import AnimatedDots from '../components/AnimatedDots.vue';

const provisionModel = ProvisionModel.create();

const ipProviders = [
  { name: 'Disabled', value: 'noop' },
  { name: 'Public IP', value: 'generic' },
  { name: 'Static IP Address', value: 'fixed' },
  { name: 'Network Interface', value: 'network-interface' }
];

const serverProvider = ref('');
const formError = ref({});
const busy = ref(false);
const ready = ref(false);
const waitingForDnsSetup = ref(false);
const progressMessage = ref('');
const taskMinutesActive = ref(0);
const domain = ref('');
const instanceId = ref('');
const zoneName = ref('');
const provider = ref('');
const dnsConfig = ref(DomainsModel.createEmptyConfig());
const tlsProvider = ref('letsencrypt-prod-wildcard');
const showAdvanced = ref(false);
const customNameservers = ref(false);
const ipv4Provider = ref('generic');
const ipv4Address = ref('');
const ipv4Interface = ref('');
const ipv6Provider = ref('generic');
const ipv6Address = ref('');
const ipv6Interface = ref('');

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

async function waitForDnsSetup () {
  waitingForDnsSetup.value = true;
  formError.value = {};

  const [error, result] = await provisionModel.status();
  if (error) {
    setTimeout(waitForDnsSetup, 5000);
    return console.error(error);
  }

  if (!result.setup.active) {
    if (!result.adminFqdn || result.setup.errorMessage) { // setup reset or errored. start over
      formError.value.generic = result.setup.errorMessage;
      waitingForDnsSetup.value = false;
    } else { // proceed to activation
      window.location.href = 'https://' + result.adminFqdn + '/activation.html' + (window.location.search);
    }
    return;
  }

  progressMessage.value = result.setup.message;
  taskMinutesActive.value = (new Date() - new Date(result.setup.startTime)) / 60000;

  setTimeout(waitForDnsSetup, 5000);
}

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

  busy.value = true;
  formError.value = {};

  const data = {
    domainConfig: {
      domain: domain.value,
      zoneName: zoneName.value,
      provider: provider.value,
      config: DomainsModel.filterConfigForProvider(provider.value, dnsConfig.value),
      tlsConfig: {
        provider: tlsProvider.value.replace('-wildcard', ''),
        wildcard: tlsProvider.value.indexOf('-wildcard') !== -1 ? true : false,
      },
    },
    ipv4Config: {
      provider: ipv4Provider.value,
      ip: ipv4Provider.value === 'fixed' ? ipv4Address.value : '',
      ifname: ipv4Provider.value === 'network-interface' ? ipv4Interface.value : '',
    },
    ipv6Config: {
      provider: ipv6Provider.value,
      ip: ipv6Provider.value === 'fixed' ? ipv6Address.value : '',
      ifname: ipv6Provider.value === 'network-interface' ? ipv6Interface.value : '',
    },
    providerToken: instanceId.value, // currently only for AMI
  };

  const [error] = await provisionModel.setup(data);
  busy.value = false; // so we can come back to this view if dns setup errors later
  if (error) {
    formError.value.generic = error.body ? error.body.message : 'Internal error';
    return;
  }

  waitForDnsSetup();
}

function onCopyToClipboard(value) {
  copyToClipboard(value);
  window.pankow.notify('Copied');
}

watchEffect(() => {
  if (dnsConfig.value.credentials) setTimeout(checkValidity, 100);
});

onMounted(async () => {
  const [error, status] = await provisionModel.status();
  if (error) return console.error(error);

  if (redirectIfNeeded(status, 'setup')) return; // redirected to some other view...

  serverProvider.value = status.provider;
  if (serverProvider.value === 'digitalocean' || serverProvider.value === 'digitalocean-mp') {
    provider.value = 'digitalocean';
  } else if (serverProvider.value === 'linode' || serverProvider.value === 'linode-oneclick' || serverProvider.value === 'linode-stackscript') {
    provider.value = 'linode';
  } else if (serverProvider.value === 'vultr' || serverProvider.value === 'vultr-mp') {
    provider.value = 'vultr';
  } else if (serverProvider.value === 'gce') {
    provider.value = 'gcdns';
  } else if (serverProvider.value === 'ami') {
    // aws marketplace made a policy change that they one cannot provide route53 IAM credentials
    // we used to have wildcard here but it shows some ugly warnings
  }

  const [error2, result] = await provisionModel.detectIp();
  if (error2) return console.error(error2); // detectIp is not supposed to error

  ipv4Provider.value = result.ipv4 ? 'generic' : 'noop';
  ipv6Provider.value = result.ipv6 ? 'generic' : 'noop';

  ready.value = true;

  if (status.setup.active) return waitForDnsSetup();
  formError.value.generic = status.setup.errorMessage; // show any previous error
});

</script>

<template>
  <div class="container" v-if="ready">
    <Notification />

    <Transition name="fade-scale" mode="out-in">
      <div class="view" v-if="waitingForDnsSetup" style="max-width: unset; height: 100%;">
        <div style="display: flex; flex-direction: column; height: 100%; align-items: center;">
          <Whirlpool/>
          <h1>Please wait while Cloudron is setting up the dashboard <AnimatedDots/></h1>
          <h4 style="margin-top: 0">{{ progressMessage }}</h4>
          <small>You can follow the logs on the server at <code @click="onCopyToClipboard('/home/yellowtent/platformdata/logs/box.log')">/home/yellowtent/platformdata/logs/box.log</code></small>
        </div>
      </div>

      <div class="view" v-else style="max-width: 500px">
        <h1 style="text-align: center">Domain Setup</h1>

        <div class="text-danger" v-if="formError.generic">{{ formError.generic }}</div>

        <form ref="form" @submit.prevent="onSubmit()" @input="checkValidity()">
          <fieldset :disabled="busy">
            <input type="submit" style="display: none"/>

            <FormGroup v-if="serverProvider === 'ami'">
              <label for="amiInstanceIdInput">EC2 Instance ID</label>
              <TextInput id="amiInstanceIdInput" v-model="instanceId" placeholder="i-0123456789abcdef0" required />
              <small class="helper-text">Can be found in the AWS Console</small>
            </FormGroup>

            <FormGroup>
              <label for="domainInput">Domain  <sup><a href="https://docs.cloudron.io/installation/#domain-setup" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
              <TextInput id="domainInput" v-model="domain" placeholder="example.com" required />
              <div class="text-danger" v-show="domain.indexOf('my.') === 0 && domain.length > 3">Are you sure about this domain? The dashboard will be at <b>my.{{ domain }}</b></div>
              <small class="helper-text">The dashboard will be available at
                <span v-if="!domain">the "my" subdomain</span>
                <span v-else>"my.{{ domain }}"</span>.
                Apps will be installed on subdomains of <span v-if="!domain">this domain</span><span v-else>"{{ domain }}"</span>. You can add more domains later.
              </small>
            </FormGroup>

            <DomainProviderForm :disabled="busy" v-model:provider="provider" v-model:dns-config="dnsConfig" v-model:tls-provider="tlsProvider" v-model:zone-name="zoneName" v-model:custom-nameservers="customNameservers" :domain="domain" :show-advanced="showAdvanced" />

            <div v-show="showAdvanced">
              <!-- IPv4 provider -->
              <FormGroup>
                <label class="control-label">IPv4 Configuration  <sup><a href="https://docs.cloudron.io/network/#ip-configuration" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
                <SingleSelect v-model="ipv4Provider" :options="ipProviders" option-key="value" option-label="name" />
              </FormGroup>

              <!-- IPv4 Fixed -->
              <FormGroup v-if="ipv4Provider === 'fixed'">
                <label for="ipv4AddressInput">IPv4 Address</label>
                <TextInput id="ipv4AddressInput" v-model="ipv4Address" required />
              </FormGroup>

              <!-- IPv4 Network Interface -->
              <FormGroup v-if="ipv4Provider === 'network-interface'">
                <label for="ipv4InterfaceInput">IPv4 Interface Name</label>
                <TextInput id="ipv4InterfaceInput" v-model="ipv4Interface" required />
              </FormGroup>

              <!-- IPv6 provider -->
              <FormGroup>
                <label class="control-label">IPv6 Configuration  <sup><a href="https://docs.cloudron.io/network/#ip-configuration" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
                <SingleSelect v-model="ipv6Provider" :options="ipProviders" option-key="value" option-label="name" />
              </FormGroup>

              <!-- IPv6 Fixed -->
              <FormGroup v-if="ipv6Provider === 'fixed'">
                <label for="ipv6AddressInput">IPv6 Address</label>
                <TextInput id="ipv6AddressInput" v-model="ipv6Address" required />
              </FormGroup>

              <!-- IPv6 Network Interface -->
              <FormGroup v-if="ipv6Provider === 'network-interface'">
                <label for="ipv6InterfaceInpt">IPv6 Interface Name</label>
                <TextInput id="ipv6InterfaceInpt" v-model="ipv6Interface" required />
              </FormGroup>
            </div>

            <div v-if="!showAdvanced" style="margin-top: 15px" class="actionable" @click="showAdvanced = true">Advanced settings...</div>
          </fieldset>
        </form>

        <div class="actions">
          <Button @click="onSubmit()" :disabled="busy || !isFormValid" :loading="busy">Next</Button>
          <a class="restore" href="/restore.html">Looking to restore?</a>
        </div>
      </div>
    </Transition>
  </div>
</template>

<style scoped>

.actions {
  margin-top: 1.5em;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.actions .restore {
  margin-top: 1em;
  font-size: 0.9em;
}

</style>
