<script lang="ts" context="module">
  export const matchingProps = ['conid'];
</script>

<script lang="ts">
  import FormButton from '../forms/FormButton.svelte';
  import FontIcon from '../icons/FontIcon.svelte';
  import TabControl from '../elements/TabControl.svelte';
  import ConnectionModalDriverFields from '../modals/ConnectionModalDriverFields.svelte';
  import ConnectionModalSshTunnelFields from '../modals/ConnectionModalSshTunnelFields.svelte';
  import ConnectionModalSslFields from '../modals/ConnectionModalSslFields.svelte';
  import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';

  import { showModal } from '../modals/modalTools';
  import createRef from '../utility/createRef';
  import Link from '../elements/Link.svelte';
  import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
  import { writable } from 'svelte/store';
  import FormProviderCore from '../forms/FormProviderCore.svelte';
  import { extensions, getCurrentConfig, openedTabs } from '../stores';
  import _, { Dictionary } from 'lodash';
  import { apiCall } from '../utility/api';
  import { showSnackbarSuccess } from '../utility/snackbar';
  import { changeTab } from '../utility/common';
  import getConnectionLabel from '../utility/getConnectionLabel';
  import { onMount } from 'svelte';
  import { openConnection } from '../appobj/ConnectionAppObject.svelte';
  import { closeMultipleTabs } from '../widgets/TabsPanel.svelte';

  export let connection;
  export let tabid;
  export let conid;

  let isTesting;
  let sqlConnectResult;

  const values = writable(
    connection || {
      server: getCurrentConfig().isDocker ? 'dockerhost' : 'localhost',
      engine: '',
    }
  );

  $: engine = $values.engine;
  $: driver = $extensions.drivers.find(x => x.engine == engine);

  const testIdRef = createRef(0);

  async function handleTest(e) {
    isTesting = true;
    testIdRef.update(x => x + 1);
    const testid = testIdRef.get();
    const resp = await apiCall('connections/test', e.detail);
    if (testIdRef.get() != testid) return;

    isTesting = false;
    sqlConnectResult = resp;
  }

  function handleCancelTest() {
    testIdRef.update(x => x + 1); // invalidate current test
    isTesting = false;
  }

  function getCurrentConnection() {
    const allProps = [
      'databaseFile',
      'useDatabaseUrl',
      'databaseUrl',
      'authType',
      'server',
      'port',
      'user',
      'password',
      'defaultDatabase',
      'singleDatabase',
    ];
    const visibleProps = allProps.filter(x => driver?.showConnectionField(x, $values));
    const omitProps = _.difference(allProps, visibleProps);
    if (!$values.defaultDatabase) omitProps.push('singleDatabase');

    let connection: Dictionary<string | boolean> = _.omit($values, omitProps);
    if (driver?.beforeConnectionSave) connection = driver?.beforeConnectionSave(connection);

    if (!driver?.showConnectionTab('sshTunnel', $values)) {
      if (!$values.useSshTunnel) {
        connection = _.omitBy(connection, (v, k) => k.startsWith('ssh'));
      }
    } else {
      connection = _.omit(connection, ['useSshTunnel']);
      connection = _.omitBy(connection, (v, k) => k.startsWith('ssh'));
    }

    if (!driver?.showConnectionTab('ssl', $values)) {
      if (!$values.useSsl) {
        connection = _.omitBy(connection, (v, k) => k.startsWith('ssl'));
      }
    } else {
      connection = _.omit(connection, ['useSsl']);
      connection = _.omitBy(connection, (v, k) => k.startsWith('ssl'));
    }

    return connection;
  }

  async function handleSave() {
    let connection = getCurrentConnection();
    connection = {
      ...connection,
      unsaved: false,
    };
    const saved = await apiCall('connections/save', connection);
    $values = {
      ...$values,
      _id: saved._id,
      unsaved: false,
    };
    changeTab(tabid, tab => ({
      ...tab,
      title: getConnectionLabel(saved),
      props: {
        ...tab.props,
        conid: saved._id,
      },
    }));
    showSnackbarSuccess('Connection saved');
  }

  async function handleConnect() {
    let connection = getCurrentConnection();
    if (!connection._id) {
      connection = {
        ...connection,
        unsaved: !connection._id,
      };
    }
    const saved = await apiCall('connections/save', connection);
    openConnection(saved);
    closeMultipleTabs(x => x.tabid == tabid, true);
  }

  onMount(async () => {
    if (conid) {
      $values = await apiCall('connections/get', { conid });
    }
  });
</script>

<FormProviderCore template={FormFieldTemplateLarge} {values}>
  <div class="wrapper">
    <TabControl
      isInline
      containerMaxWidth="800px"
      flex1={false}
      tabs={[
        {
          label: 'General',
          component: ConnectionModalDriverFields,
        },
        driver?.showConnectionTab('sshTunnel', $values) && {
          label: 'SSH Tunnel',
          component: ConnectionModalSshTunnelFields,
        },
        driver?.showConnectionTab('ssl', $values) && {
          label: 'SSL',
          component: ConnectionModalSslFields,
        },
      ]}
    />

    {#if driver}
      <div class="flex">
        <div class="buttons">
          <FormButton value="Connect" on:click={handleConnect} />
          {#if isTesting}
            <FormButton value="Cancel test" on:click={handleCancelTest} />
          {:else}
            <FormButton value="Test" on:click={handleTest} />
          {/if}
          <FormButton value="Save" on:click={handleSave} />
        </div>
        <div class="test-result">
          {#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'connected'}
            <div>
              Connected: <FontIcon icon="img ok" />
              {sqlConnectResult.version}
            </div>
          {/if}
          {#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'}
            <div class="error-result">
              Connect failed: <FontIcon icon="img error" />
              {sqlConnectResult.error}
              <Link
                onClick={() =>
                  showModal(ErrorMessageModal, {
                    message: sqlConnectResult.detail,
                    showAsCode: true,
                    title: 'Database connection error',
                  })}
              >
                Show detail
              </Link>
            </div>
          {/if}
          {#if isTesting}
            <div>
              <FontIcon icon="icon loading" /> Testing connection
            </div>
          {/if}
        </div>
      </div>
    {/if}
  </div>
</FormProviderCore>

<style>
  .wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
  }

  .buttons {
    flex-shrink: 0;
    margin: var(--dim-large-form-margin);
  }

  .test-result {
    margin-left: 10px;
    align-self: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .error-result {
    white-space: normal;
  }
</style>
