<script lang="ts">
  import SupportedDatetimePanel from '$lib/components/admin-settings/SupportedDatetimePanel.svelte';
  import SupportedVariablesPanel from '$lib/components/admin-settings/SupportedVariablesPanel.svelte';
  import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
  import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte';
  import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
  import { AppRoute, SettingInputFieldType } from '$lib/constants';
  import FormatMessage from '$lib/elements/FormatMessage.svelte';
  import { user } from '$lib/stores/user.store';
  import {
    getStorageTemplateOptions,
    type SystemConfigDto,
    type SystemConfigTemplateStorageOptionDto,
  } from '@immich/sdk';
  import { LoadingSpinner } from '@immich/ui';
  import handlebar from 'handlebars';
  import { isEqual } from 'lodash-es';
  import * as luxon from 'luxon';
  import type { Snippet } from 'svelte';
  import { t } from 'svelte-i18n';
  import { createBubbler, preventDefault } from 'svelte/legacy';
  import { fade } from 'svelte/transition';
  import type { SettingsResetEvent, SettingsSaveEvent } from './admin-settings';

  interface Props {
    savedConfig: SystemConfigDto;
    defaultConfig: SystemConfigDto;
    config: SystemConfigDto;
    disabled?: boolean;
    minified?: boolean;
    onReset: SettingsResetEvent;
    onSave: SettingsSaveEvent;
    duration?: number;
    children?: Snippet;
  }

  let {
    savedConfig,
    defaultConfig,
    config = $bindable(),
    disabled = false,
    minified = false,
    onReset,
    onSave,
    duration = 500,
    children,
  }: Props = $props();

  const bubble = createBubbler();
  let templateOptions: SystemConfigTemplateStorageOptionDto | undefined = $state();
  let selectedPreset = $state('');

  const getTemplateOptions = async () => {
    templateOptions = await getStorageTemplateOptions();
    selectedPreset = savedConfig.storageTemplate.template;
  };

  const getSupportDateTimeFormat = () => getStorageTemplateOptions();

  const renderTemplate = (templateString: string) => {
    if (!templateOptions) {
      return '';
    }

    const template = handlebar.compile(templateString, {
      knownHelpers: undefined,
    });

    const substitutions: Record<string, string> = {
      filename: 'IMAGE_56437',
      ext: 'jpg',
      filetype: 'IMG',
      filetypefull: 'IMAGE',
      assetId: 'a8312960-e277-447d-b4ea-56717ccba856',
      assetIdShort: '56717ccba856',
      album: $t('album_name'),
    };

    const dt = luxon.DateTime.fromISO(new Date('2022-02-03T04:56:05.250').toISOString());
    const albumStartTime = luxon.DateTime.fromISO(new Date('2021-12-31T05:32:41.750').toISOString());
    const albumEndTime = luxon.DateTime.fromISO(new Date('2023-05-06T09:15:17.100').toISOString());

    const dateTokens = [
      ...templateOptions.yearOptions,
      ...templateOptions.monthOptions,
      ...templateOptions.weekOptions,
      ...templateOptions.dayOptions,
      ...templateOptions.hourOptions,
      ...templateOptions.minuteOptions,
      ...templateOptions.secondOptions,
    ];

    for (const token of dateTokens) {
      substitutions[token] = dt.toFormat(token);
      substitutions['album-startDate-' + token] = albumStartTime.toFormat(token);
      substitutions['album-endDate-' + token] = albumEndTime.toFormat(token);
    }

    return template(substitutions);
  };

  const handlePresetSelection = () => {
    config.storageTemplate.template = selectedPreset;
  };
  let parsedTemplate = $derived(() => {
    try {
      return renderTemplate(config.storageTemplate.template);
    } catch {
      return 'error';
    }
  });
</script>

<section class="dark:text-immich-dark-fg mt-2">
  <div in:fade={{ duration }} class="mx-4 flex flex-col gap-4 py-4">
    <p class="text-sm dark:text-immich-dark-fg">
      <FormatMessage key="admin.storage_template_more_details">
        {#snippet children({ tag, message })}
          {#if tag === 'template-link'}
            <a
              href="https://immich.app/docs/administration/storage-template"
              class="underline"
              target="_blank"
              rel="noreferrer"
            >
              {message}
            </a>
          {:else if tag === 'implications-link'}
            <a
              href="https://immich.app/docs/administration/backup-and-restore#asset-types-and-storage-locations"
              class="underline"
              target="_blank"
              rel="noreferrer"
            >
              {message}
            </a>
          {/if}
        {/snippet}
      </FormatMessage>
    </p>
  </div>
  {#await getTemplateOptions() then}
    <div id="directory-path-builder" class="flex flex-col gap-4 {minified ? '' : 'ms-4 mt-4'}">
      <SettingSwitch
        title={$t('admin.storage_template_enable_description')}
        {disabled}
        bind:checked={config.storageTemplate.enabled}
        isEdited={!(config.storageTemplate.enabled === savedConfig.storageTemplate.enabled)}
      />

      {#if !minified}
        <SettingSwitch
          title={$t('admin.storage_template_hash_verification_enabled')}
          {disabled}
          subtitle={$t('admin.storage_template_hash_verification_enabled_description')}
          bind:checked={config.storageTemplate.hashVerificationEnabled}
          isEdited={!(
            config.storageTemplate.hashVerificationEnabled === savedConfig.storageTemplate.hashVerificationEnabled
          )}
        />
      {/if}

      {#if config.storageTemplate.enabled}
        <hr />

        <h3 class="text-base font-medium text-immich-primary dark:text-immich-dark-primary">{$t('variables')}</h3>

        <section class="support-date">
          {#await getSupportDateTimeFormat()}
            <LoadingSpinner />
          {:then options}
            <div transition:fade={{ duration: 200 }}>
              <SupportedDatetimePanel {options} />
            </div>
          {/await}
        </section>

        <section class="support-date">
          <SupportedVariablesPanel />
        </section>

        <div class="flex flex-col mt-4">
          <h3 class="text-base font-medium text-immich-primary dark:text-immich-dark-primary">{$t('template')}</h3>

          <div class="my-2 text-sm">
            <h4 class="uppercase">{$t('preview')}</h4>
          </div>

          <p class="text-sm">
            <FormatMessage
              key="admin.storage_template_path_length"
              values={{ length: parsedTemplate().length + $user.id.length + 'UPLOAD_LOCATION'.length, limit: 260 }}
            >
              {#snippet children({ message })}
                <span class="font-semibold text-immich-primary dark:text-immich-dark-primary">{message}</span>
              {/snippet}
            </FormatMessage>
          </p>

          <p class="text-sm">
            <FormatMessage key="admin.storage_template_user_label" values={{ label: $user.storageLabel || $user.id }}>
              {#snippet children({ message })}
                <code class="text-immich-primary dark:text-immich-dark-primary">{message}</code>
              {/snippet}
            </FormatMessage>
          </p>

          <p class="p-4 py-2 mt-2 text-xs bg-gray-200 rounded-lg dark:bg-gray-700 dark:text-immich-dark-fg">
            <span class="text-immich-fg/25 dark:text-immich-dark-fg/50"
              >UPLOAD_LOCATION/library/{$user.storageLabel || $user.id}</span
            >/{parsedTemplate()}.jpg
          </p>

          <form autocomplete="off" class="flex flex-col" onsubmit={preventDefault(bubble('submit'))}>
            <div class="flex flex-col my-2">
              {#if templateOptions}
                <label
                  class="font-medium text-immich-primary dark:text-immich-dark-primary text-sm"
                  for="preset-select"
                >
                  {$t('preset')}
                </label>
                <select
                  class="immich-form-input p-2 mt-2 text-sm rounded-lg bg-slate-200 hover:cursor-pointer dark:bg-gray-600"
                  disabled={disabled || !config.storageTemplate.enabled}
                  name="presets"
                  id="preset-select"
                  bind:value={selectedPreset}
                  onchange={handlePresetSelection}
                >
                  {#each templateOptions.presetOptions as preset (preset)}
                    <option value={preset}>{renderTemplate(preset)}</option>
                  {/each}
                </select>
              {/if}
            </div>

            <div class="flex gap-2 align-bottom">
              <SettingInputField
                label={$t('template')}
                disabled={disabled || !config.storageTemplate.enabled}
                required
                inputType={SettingInputFieldType.TEXT}
                bind:value={config.storageTemplate.template}
                isEdited={!(config.storageTemplate.template === savedConfig.storageTemplate.template)}
              />

              <div class="flex-0">
                <SettingInputField
                  label={$t('extension')}
                  inputType={SettingInputFieldType.TEXT}
                  value=".jpg"
                  disabled
                />
              </div>
            </div>

            {#if !minified}
              <div id="migration-info" class="mt-2 text-sm">
                <h3 class="text-base font-medium text-immich-primary dark:text-immich-dark-primary">{$t('notes')}</h3>
                <section class="flex flex-col gap-2">
                  <p>
                    <FormatMessage
                      key="admin.storage_template_migration_info"
                      values={{ job: $t('admin.storage_template_migration_job') }}
                    >
                      {#snippet children({ message })}
                        <a href={AppRoute.ADMIN_JOBS} class="text-immich-primary dark:text-immich-dark-primary">
                          {message}
                        </a>
                      {/snippet}
                    </FormatMessage>
                  </p>
                </section>
              </div>
            {/if}
          </form>
        </div>
      {/if}

      {#if minified}
        {@render children?.()}
      {:else}
        <SettingButtonsRow
          onReset={(options) => onReset({ ...options, configKeys: ['storageTemplate'] })}
          onSave={() => onSave({ storageTemplate: config.storageTemplate })}
          showResetToDefault={!isEqual(savedConfig.storageTemplate, defaultConfig.storageTemplate) && !minified}
          {disabled}
        />
      {/if}
    </div>
  {/await}
</section>
