<script lang="ts">
  import { onMount } from 'svelte';

  import FormStyledButton from '../buttons/FormStyledButton.svelte';
  import FormProvider from '../forms/FormProvider.svelte';

  import ModalBase from './ModalBase.svelte';
  import { closeCurrentModal } from './modalTools';
  import { _t } from '../translations';
  import { apiCall } from '../utility/api';
  import TabControl from '../elements/TabControl.svelte';
  import TableControl from '../elements/TableControl.svelte';
  import { writable } from 'svelte/store';
  import LargeButton from '../buttons/LargeButton.svelte';
  import { downloadFromApi } from '../utility/exportFileTools';
  import getElectron from '../utility/getElectron';
  import { showSnackbarSuccess } from '../utility/snackbar';
  import { format } from 'date-fns';
  import Link from '../elements/Link.svelte';
  import _ from 'lodash';

  export let mode: 'export' | 'import';
  export let uploadedFilePath = undefined;

  let fullData: any = {};

  async function loadExportedData() {
    fullData = await apiCall('config/export-connections-and-settings');
    initFromFullData();
  }

  async function loadImportedData() {
    fullData = await apiCall('files/get-jsons-from-zip', { filePath: uploadedFilePath });
    initFromFullData();
  }

  function initFromFullData() {
    connections = fullData.connections || [];
    users = fullData.users || [];
    roles = fullData.roles || [];
    authMethods = fullData.auth_methods || [];
    config = fullData.config || [];

    handleCheckAll(true);
  }

  function handleCheckAll(checked) {
    if (checked) {
      checkedConnections = connections.map(x => x.id);
      checkedUsers = users.map(x => x.id);
      checkedRoles = roles.map(x => x.id);
      checkedAuthMethods = authMethods.map(x => x.id);
      checkedConfig = config.map(x => x.id);
    } else {
      checkedConnections = [];
      checkedUsers = [];
      checkedRoles = [];
      checkedAuthMethods = [];
      checkedConfig = [];
    }
  }

  onMount(() => {
    if (mode == 'export') {
      loadExportedData();
    }
    if (mode == 'import') {
      loadImportedData();
    }
  });

  function getLimitedData() {
    const limitedData: any = {
      connections: fullData.connections?.filter(x => checkedConnections.includes(x.id)),

      users: fullData.users?.filter(x => checkedUsers.includes(x.id)),

      user_connections: fullData.user_connections?.filter(
        x => checkedUsers.includes(x.user_id) && checkedConnections.includes(x.connection_id)
      ),
      user_roles: fullData.user_roles?.filter(x => checkedUsers.includes(x.user_id) && checkedRoles.includes(x.role_id)),
      user_permissions: fullData.user_permissions?.filter(x => checkedUsers.includes(x.user_id)),

      roles: fullData.roles?.filter(x => checkedRoles.includes(x.id)),
      role_connections: fullData.role_connections?.filter(
        x => checkedRoles.includes(x.role_id) && checkedConnections.includes(x.connection_id)
      ),
      role_permissions: fullData.role_permissions?.filter(x => checkedRoles.includes(x.role_id)),

      auth_methods: fullData.auth_methods?.filter(x => checkedAuthMethods.includes(x.id)),
      auth_methods_config: fullData.auth_methods_config?.filter(x => checkedAuthMethods.includes(x.auth_method_id)),

      config: fullData.config?.filter(
        x => checkedConfig.includes(x.id) || (x.group == 'admin' && x.key == 'encryptionKey')
      ),
    };
    return limitedData;
  }

  async function handleExport() {
    const electron = getElectron();

    let filePath;
    let fileName;

    if (electron) {
      const electron = getElectron();
      filePath = await electron.showSaveDialog({
        filters: [
          { name: `ZIP files`, extensions: ['zip'] },
          { name: `All files`, extensions: ['*'] },
        ],
        defaultPath: `dbgateconfig.zip`,
        properties: ['showOverwriteConfirmation'],
      });
    } else {
      const resp = await apiCall('files/generate-uploads-file', { extension: 'sql' });
      filePath = resp.filePath;
      fileName = resp.fileName;
    }

    if (!filePath) {
      return;
    }

    await apiCall('files/create-zip-from-jsons', { db: getLimitedData(), filePath });

    if (electron) {
      showSnackbarSuccess(`Saved to file ${filePath}`);
    } else {
      await downloadFromApi(`uploads/get?file=${fileName}`, `dbgateconfig.zip`);
    }
  }

  async function handleSaveToArchive() {
    const filePath = `archive:dbgateconfig-${format(new Date(), 'yyyy-MM-dd-HH-mm-ss')}.zip`;
    await apiCall('files/create-zip-from-jsons', { db: getLimitedData(), filePath });
    showSnackbarSuccess(`Saved to ${filePath}`);
  }

  async function handleImport() {
    await apiCall('config/import-connections-and-settings', { db: getLimitedData() });
    showSnackbarSuccess(`Imported connections and settings`);
  }

  let connections = [];
  let checkedConnections = [];

  let users = [];
  let checkedUsers = [];

  let roles = [];
  let checkedRoles = [];

  let authMethods = [];
  let checkedAuthMethods = [];

  let config = [];
  let checkedConfig = [];

  const connectionFilters = writable({});
  const userFilters = writable({});
  const roleFilters = writable({});
  const authMethodFilters = writable({});
  const configFilters = writable({});
</script>

<FormProvider>
  <ModalBase {...$$restProps} fullScreen>
    <div slot="header">
      {mode == 'export' ? 'Export' : 'Import'} {_t('importExport.connectionsSettings', { defaultMessage: 'connections & settings' })}
      <span class="check-uncheck">
        <Link onClick={() => handleCheckAll(true)}>{_t('common.checkAll', { defaultMessage: 'Check all' })}</Link>
        |
        <Link onClick={() => handleCheckAll(false)}>{_t('common.uncheckAll', { defaultMessage: 'Uncheck all' })}</Link>
      </span>
    </div>

    <div class="tabs">
      <TabControl
        tabs={_.compact([
          connections?.length && {
            label: _t('importExport.connectionsNum', { defaultMessage:'Connections ({checkedConnections}/{connections})', values: { checkedConnections: checkedConnections?.length, connections: connections?.length } }),
            slot: 1,
          },
          users?.length && { label: _t('importExport.usersNum', { defaultMessage:'Users ({checkedUsers}/{users})', values: { checkedUsers: checkedUsers?.length, users: users?.length } }), slot: 2 },
          roles?.length && { label: _t('importExport.rolesNum', { defaultMessage:'Roles ({checkedRoles}/{roles})', values: { checkedRoles: checkedRoles?.length, roles: roles?.length } }), slot: 3 },
          authMethods?.length && {
            label: _t('importExport.authMethodsNum', { defaultMessage:'Auth methods ({checkedAuthMethods}/{authMethods})', values: { checkedAuthMethods: checkedAuthMethods?.length, authMethods: authMethods?.length } }),
            slot: 4,
          },
          config?.length && { label: _t('importExport.configNum', { defaultMessage:'Config ({checkedConfig}/{config})', values: { checkedConfig: checkedConfig?.length, config: config?.length } }), slot: 5 },
        ])}
      >
        <svelte:fragment slot="1">
          <div class="tablewrap">
            <TableControl
              filters={connectionFilters}
              stickyHeader
              columns={[
                { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
                { header: _t('importExport.displayName', { defaultMessage: 'Display name' }), fieldName: 'displayName', sortable: true, filterable: true },
                { header: _t('importExport.engine', { defaultMessage: 'Engine' }), fieldName: 'engine', sortable: true, filterable: true },
                { header: _t('importExport.server', { defaultMessage: 'Server' }), fieldName: 'server', sortable: true, filterable: true },
                { header: _t('importExport.user', { defaultMessage: 'User' }), fieldName: 'user', sortable: true, filterable: true },
              ]}
              clickable
              rows={connections}
              on:clickrow={event => {
                checkedConnections = checkedConnections.includes(event.detail.id)
                  ? checkedConnections.filter(id => id !== event.detail.id)
                  : [...checkedConnections, event.detail.id];
              }}
              checkedKeys={checkedConnections}
              onSetCheckedKeys={keys => {
                checkedConnections = keys;
              }}
            ></TableControl>
          </div>
        </svelte:fragment>
        <svelte:fragment slot="2">
          <div class="tablewrap">
            <TableControl
              filters={userFilters}
              stickyHeader
              columns={[
                { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
                { header: _t('importExport.login', { defaultMessage: 'Login' }), fieldName: 'login', sortable: true, filterable: true },
                { header: _t('importExport.email', { defaultMessage: 'E-mail' }), fieldName: 'email', sortable: true, filterable: true },
              ]}
              clickable
              rows={users}
              on:clickrow={event => {
                checkedUsers = checkedUsers.includes(event.detail.id)
                  ? checkedUsers.filter(id => id !== event.detail.id)
                  : [...checkedUsers, event.detail.id];
              }}
              checkedKeys={checkedUsers}
              onSetCheckedKeys={keys => {
                checkedUsers = keys;
              }}
            ></TableControl>
          </div>
        </svelte:fragment>
        <svelte:fragment slot="3">
          <div class="tablewrap">
            <TableControl
              filters={roleFilters}
              stickyHeader
              columns={[
                { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
                { header: _t('importExport.name', { defaultMessage: 'Name' }), fieldName: 'name', sortable: true, filterable: true },
              ]}
              clickable
              rows={roles}
              on:clickrow={event => {
                checkedRoles = checkedRoles.includes(event.detail.id)
                  ? checkedRoles.filter(id => id !== event.detail.id)
                  : [...checkedRoles, event.detail.id];
              }}
              checkedKeys={checkedRoles}
              onSetCheckedKeys={keys => {
                checkedRoles = keys;
              }}
            ></TableControl>
          </div>
        </svelte:fragment>
        <svelte:fragment slot="4">
          <div class="tablewrap">
            <TableControl
              filters={authMethodFilters}
              stickyHeader
              columns={[
                { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
                { header: _t('importExport.name', { defaultMessage: 'Name' }), fieldName: 'name', sortable: true, filterable: true },
                { header: _t('importExport.type', { defaultMessage: 'Type' }), fieldName: 'type', sortable: true, filterable: true },
              ]}
              clickable
              rows={authMethods}
              on:clickrow={event => {
                checkedAuthMethods = checkedAuthMethods.includes(event.detail.id)
                  ? checkedAuthMethods.filter(id => id !== event.detail.id)
                  : [...checkedAuthMethods, event.detail.id];
              }}
              checkedKeys={checkedAuthMethods}
              onSetCheckedKeys={keys => {
                checkedAuthMethods = keys;
              }}
            ></TableControl>
          </div>
        </svelte:fragment>
        <svelte:fragment slot="5">
          <div class="tablewrap">
            <TableControl
              filters={configFilters}
              stickyHeader
              columns={[
                { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
                { header: _t('importExport.group', { defaultMessage: 'Group' }), fieldName: 'group', sortable: true, filterable: true },
                { header: _t('importExport.key', { defaultMessage: 'Key' }), fieldName: 'key', sortable: true, filterable: true },
                { header: _t('importExport.value', { defaultMessage: 'Value' }), fieldName: 'value', sortable: true, filterable: true },
              ]}
              clickable
              rows={config}
              on:clickrow={event => {
                checkedConfig = checkedConfig.includes(event.detail.id)
                  ? checkedConfig.filter(id => id !== event.detail.id)
                  : [...checkedConfig, event.detail.id];
              }}
              checkedKeys={checkedConfig}
              onSetCheckedKeys={keys => {
                checkedConfig = keys;
              }}
            ></TableControl>
          </div>
        </svelte:fragment>
      </TabControl>
    </div>

    <div slot="footer">
      <div class="flex m-2">
        {#if mode == 'export'}
          <LargeButton
            data-testid="ExportImportConnectionsModal_exportButton"
            icon="icon export"
            on:click={handleExport}>{_t('common.export', { defaultMessage: 'Export' })}</LargeButton
          >
          <LargeButton
            data-testid="ExportImportConnectionsModal_saveToArchive"
            icon="icon archive"
            on:click={handleSaveToArchive}
            >{_t('common.saveToArchive', { defaultMessage: 'Save to archive' })}</LargeButton
          >
        {/if}
        {#if mode == 'import'}
          <LargeButton
            data-testid="ExportImportConnectionsModal_importButton"
            icon="icon import"
            on:click={handleImport}>{_t('common.import', { defaultMessage: 'Import' })}</LargeButton
          >
        {/if}
        <LargeButton icon="icon close" on:click={closeCurrentModal} data-testid="EditJsonModal_closeButton"
          >{_t('common.close', { defaultMessage: 'Close' })}</LargeButton
        >
      </div>
    </div>
  </ModalBase>
</FormProvider>

<style>
  .tablewrap {
    overflow: auto;
    width: 100%;
    height: calc(100vh - 220px);
    margin: 1rem;
  }

  .tabs {
    flex: 1;
  }

  .check-uncheck {
    margin-left: 1rem;
    font-size: 0.8rem;
  }
</style>
