<script setup lang="ts">
import { useMutation, useQuery } from '@vue/apollo-composable';
import {
  CatalogProductTypeSettingsDocument,
  UpsertCatalogProductTypeSettingDocument,
  type CatalogProductTypeSettingsQuery,
} from '~/composables/graphql/generated';

definePageMeta({
  middleware: ['manager-only'],
  path: '/admin/settings/catalog',
});

type CatalogSettingItem = CatalogProductTypeSettingsQuery['catalogProductTypeSettings'][number];
type OptionKey =
  | 'widthOptionsMm'
  | 'lengthOptionsM'
  | 'thicknessOptionsMicron'
  | 'sleeveOptions'
  | 'colorOptions'
  | 'labelOptions';
type OptionKind = 'number' | 'text';
type CatalogSettingForm = {
  productType: string;
  allowCustomLength: boolean;
  customLengthMinM: string;
  customLengthMaxM: string;
  customLengthStepM: string;
  allowCustomSleeveBrand: boolean;
  allowCustomLabel: boolean;
  widthOptionsMm: string[];
  lengthOptionsM: string[];
  thicknessOptionsMicron: string[];
  sleeveOptions: string[];
  colorOptions: string[];
  labelOptions: string[];
  drafts: Record<OptionKey, string>;
};
type OptionGroupDefinition = {
  key: OptionKey;
  label: string;
  placeholder: string;
  kind: OptionKind;
  suffix?: string;
};

const OPTION_GROUPS: OptionGroupDefinition[] = [
  { key: 'widthOptionsMm', label: 'Ширина', placeholder: 'Добавить ширину', kind: 'number', suffix: 'мм' },
  { key: 'lengthOptionsM', label: 'Длина', placeholder: 'Добавить длину', kind: 'number', suffix: 'м' },
  { key: 'thicknessOptionsMicron', label: 'Толщина', placeholder: 'Добавить толщину', kind: 'number', suffix: 'мкм' },
  { key: 'sleeveOptions', label: 'Втулка', placeholder: 'Добавить втулку', kind: 'text' },
  { key: 'colorOptions', label: 'Цвет', placeholder: 'Добавить цвет', kind: 'text' },
  { key: 'labelOptions', label: 'Надпись', placeholder: 'Добавить надпись', kind: 'text' },
];

const settingsQuery = useQuery(CatalogProductTypeSettingsDocument);
const saveSettingMutation = useMutation(UpsertCatalogProductTypeSettingDocument, { throws: 'never' });

const forms = reactive<Record<string, CatalogSettingForm>>({});
const isSavingAll = ref(false);
const saveSuccess = ref('');
const saveError = ref('');

const settings = computed<CatalogSettingItem[]>(() => settingsQuery.result.value?.catalogProductTypeSettings ?? []);
const isLoading = computed(() => settingsQuery.loading.value);

function normalizeText(value: string | null | undefined) {
  return String(value ?? '').replaceAll(/\s+/g, ' ').trim();
}

function toInputValue(value: number | null | undefined) {
  return value == null ? '' : String(value);
}

function createDrafts(): Record<OptionKey, string> {
  return {
    widthOptionsMm: '',
    lengthOptionsM: '',
    thicknessOptionsMicron: '',
    sleeveOptions: '',
    colorOptions: '',
    labelOptions: '',
  };
}

function parseOptionalInteger(value: string) {
  const normalized = value.trim();
  if (!normalized) {
    return null;
  }

  const parsed = Number(normalized);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    return null;
  }

  return parsed;
}

function normalizeOptionEntry(value: string, kind: OptionKind) {
  if (kind === 'number') {
    const parsed = parseOptionalInteger(value);
    return parsed == null ? '' : String(parsed);
  }

  return normalizeText(value);
}

function normalizeOptionList(values: Array<string | number | null | undefined>, kind: OptionKind) {
  const normalizedValues = values
    .map((value) => normalizeOptionEntry(String(value ?? ''), kind))
    .filter(Boolean);

  return [...new Set(normalizedValues)].sort((left, right) => {
    if (kind === 'number') {
      return Number(left) - Number(right);
    }

    return left.localeCompare(right, 'ru');
  });
}

function createForm(item: CatalogSettingItem): CatalogSettingForm {
  return {
    productType: item.productType,
    allowCustomLength: item.allowCustomLength,
    customLengthMinM: toInputValue(item.customLengthMinM),
    customLengthMaxM: toInputValue(item.customLengthMaxM),
    customLengthStepM: toInputValue(item.customLengthStepM),
    allowCustomSleeveBrand: item.allowCustomSleeveBrand,
    allowCustomLabel: item.allowCustomLabel,
    widthOptionsMm: normalizeOptionList(item.widthOptionsMm, 'number'),
    lengthOptionsM: normalizeOptionList(item.lengthOptionsM, 'number'),
    thicknessOptionsMicron: normalizeOptionList(item.thicknessOptionsMicron, 'number'),
    sleeveOptions: normalizeOptionList(item.sleeveOptions, 'text'),
    colorOptions: normalizeOptionList(item.colorOptions, 'text'),
    labelOptions: normalizeOptionList(item.labelOptions, 'text'),
    drafts: createDrafts(),
  };
}

function formFor(item: CatalogSettingItem) {
  forms[item.productType] ??= createForm(item);
  return forms[item.productType];
}

function addOption(form: CatalogSettingForm, group: OptionGroupDefinition) {
  const value = normalizeOptionEntry(form.drafts[group.key], group.kind);
  if (!value) {
    return;
  }

  form[group.key] = normalizeOptionList([...form[group.key], value], group.kind);
  form.drafts[group.key] = '';
}

function removeOption(form: CatalogSettingForm, groupKey: OptionKey, value: string) {
  form[groupKey] = form[groupKey].filter((item) => item !== value);
}

function optionChipLabel(value: string, group: OptionGroupDefinition) {
  return group.suffix ? `${value} ${group.suffix}` : value;
}

function parseIntegerOptionList(values: string[]) {
  return normalizeOptionList(values, 'number').map((value) => Number(value));
}

function parseTextOptionList(values: string[]) {
  return normalizeOptionList(values, 'text');
}

watch(
  settings,
  (items) => {
    const activeTypes = new Set(items.map((item) => item.productType));

    for (const productType of Object.keys(forms)) {
      if (!activeTypes.has(productType)) {
        Reflect.deleteProperty(forms, productType);
      }
    }

    for (const item of items) {
      forms[item.productType] = createForm(item);
    }
  },
  { immediate: true },
);

async function saveAllSettings() {
  saveSuccess.value = '';
  saveError.value = '';
  isSavingAll.value = true;

  for (const item of settings.value) {
    const form = formFor(item);
    const result = await saveSettingMutation.mutate({
      input: {
        productType: form.productType,
        showQuantityPerBox: false,
        allowCustomLength: form.allowCustomLength,
        customLengthMinM: form.allowCustomLength ? parseOptionalInteger(form.customLengthMinM) : null,
        customLengthMaxM: form.allowCustomLength ? parseOptionalInteger(form.customLengthMaxM) : null,
        customLengthStepM: form.allowCustomLength ? parseOptionalInteger(form.customLengthStepM) : null,
        allowCustomSleeveBrand: form.allowCustomSleeveBrand,
        allowCustomLabel: form.allowCustomLabel,
        widthOptionsMm: parseIntegerOptionList(form.widthOptionsMm),
        lengthOptionsM: parseIntegerOptionList(form.lengthOptionsM),
        thicknessOptionsMicron: parseIntegerOptionList(form.thicknessOptionsMicron),
        sleeveOptions: parseTextOptionList(form.sleeveOptions),
        colorOptions: parseTextOptionList(form.colorOptions),
        labelOptions: parseTextOptionList(form.labelOptions),
      },
    });

    if (!result?.data?.upsertCatalogProductTypeSetting) {
      saveError.value = saveSettingMutation.error.value?.message || `Не удалось сохранить настройки для "${form.productType}".`;
      isSavingAll.value = false;
      return;
    }

    forms[item.productType] = createForm(result.data.upsertCatalogProductTypeSetting);
  }

  isSavingAll.value = false;
  saveSuccess.value = 'Настройки сохранены.';
}
</script>

<template>
  <section class="space-y-6">
    <h1 class="text-3xl font-extrabold text-[#0f2f20]">Каталог</h1>

    <div v-if="isLoading" class="manager-empty-state">
      Загружаем настройки каталога...
    </div>

    <div v-else-if="settings.length === 0" class="manager-empty-state">
      Типы товаров пока не появились в каталоге.
    </div>

    <div v-else class="space-y-4">
      <article
        v-for="item in settings"
        :key="item.productType"
        class="rounded-[28px] bg-white p-5 shadow-[0_18px_38px_rgba(18,56,36,0.08)]"
      >
        <div class="space-y-5">
          <h2 class="text-xl font-bold text-[#123824]">{{ item.productType }}</h2>

          <div class="space-y-3">
            <label class="surface-card flex items-center gap-3 rounded-[22px] p-4">
              <input v-model="formFor(item).allowCustomLength" type="checkbox" class="checkbox checkbox-success">
              <span class="text-sm font-semibold text-[#123824]">Любая длина</span>
            </label>

            <label class="surface-card flex items-center gap-3 rounded-[22px] p-4">
              <input v-model="formFor(item).allowCustomSleeveBrand" type="checkbox" class="checkbox checkbox-success">
              <span class="text-sm font-semibold text-[#123824]">Логотип на втулке</span>
            </label>

            <label class="surface-card flex items-center gap-3 rounded-[22px] p-4">
              <input v-model="formFor(item).allowCustomLabel" type="checkbox" class="checkbox checkbox-success">
              <span class="text-sm font-semibold text-[#123824]">Нанесение надписи</span>
            </label>
          </div>

          <div v-if="formFor(item).allowCustomLength" class="rounded-[24px] bg-[#f7fbf8] p-4">
            <div class="mb-4 text-sm font-bold uppercase tracking-[0.12em] text-[#355947]">Диапазон длины</div>
            <div class="grid gap-3 md:grid-cols-3">
              <label class="space-y-2">
                <span class="text-sm font-semibold text-[#123824]">Мин. длина, м</span>
                <input
                  v-model="formFor(item).customLengthMinM"
                  type="number"
                  min="1"
                  step="1"
                  class="input manager-field w-full"
                >
              </label>

              <label class="space-y-2">
                <span class="text-sm font-semibold text-[#123824]">Макс. длина, м</span>
                <input
                  v-model="formFor(item).customLengthMaxM"
                  type="number"
                  min="1"
                  step="1"
                  class="input manager-field w-full"
                >
              </label>

              <label class="space-y-2">
                <span class="text-sm font-semibold text-[#123824]">Шаг, м</span>
                <input
                  v-model="formFor(item).customLengthStepM"
                  type="number"
                  min="1"
                  step="1"
                  class="input manager-field w-full"
                >
              </label>
            </div>
          </div>

          <div class="rounded-[24px] bg-[#f7fbf8] p-4">
            <div class="mb-4 text-sm font-bold uppercase tracking-[0.12em] text-[#355947]">Стандартные параметры</div>

            <div class="space-y-4">
              <div
                v-for="group in OPTION_GROUPS"
                :key="`${item.productType}-${group.key}`"
                class="rounded-[20px] bg-white p-4"
              >
                <div class="space-y-3">
                  <div class="text-sm font-semibold text-[#123824]">{{ group.label }}</div>

                  <div class="flex flex-wrap gap-2">
                    <button
                      v-for="value in formFor(item)[group.key]"
                      :key="`${item.productType}-${group.key}-${value}`"
                      type="button"
                      class="inline-flex items-center gap-2 rounded-full bg-[#eef7f1] px-3 py-1 text-xs font-semibold text-[#1d5a3c]"
                      @click="removeOption(formFor(item), group.key, value)"
                    >
                      <span>{{ optionChipLabel(value, group) }}</span>
                      <span class="text-[11px] leading-none text-[#6a8a78]">×</span>
                    </button>

                    <span
                      v-if="formFor(item)[group.key].length === 0"
                      class="rounded-full border border-dashed border-[#d6e7dc] px-3 py-1 text-xs font-medium text-[#7b8f84]"
                    >
                      Пока пусто
                    </span>
                  </div>

                  <div class="flex flex-col gap-2 md:flex-row">
                    <input
                      v-model="formFor(item).drafts[group.key]"
                      :type="group.kind === 'number' ? 'number' : 'text'"
                      :min="group.kind === 'number' ? '1' : undefined"
                      :step="group.kind === 'number' ? '1' : undefined"
                      class="input manager-field w-full"
                      :placeholder="group.placeholder"
                      @keydown.enter.prevent="addOption(formFor(item), group)"
                    >
                    <button
                      type="button"
                      class="btn h-11 rounded-full border-0 bg-[#dff2e7] px-5 text-sm font-semibold text-[#155c3a] hover:bg-[#caead8]"
                      @click="addOption(formFor(item), group)"
                    >
                      Добавить
                    </button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </article>
    </div>

    <div v-if="saveSuccess || saveError" class="space-y-2 text-sm">
      <p v-if="saveSuccess" class="font-semibold text-[#1c6b45]">{{ saveSuccess }}</p>
      <p v-if="saveError" class="font-semibold text-[#c4472d]">{{ saveError }}</p>
    </div>

    <div v-if="settings.length" class="flex justify-end">
      <button
        class="btn h-11 rounded-full border-0 bg-[#139957] px-6 text-sm font-semibold text-white hover:bg-[#0d854a]"
        :disabled="isSavingAll"
        @click="saveAllSettings"
      >
        {{ isSavingAll ? 'Сохраняем…' : 'Сохранить' }}
      </button>
    </div>
  </section>
</template>
