<script setup>
import { useLayout } from "../../layout/composables/layout";
import { $t, updatePreset, updateSurfacePalette } from "@primeuix/themes";
import Aura from "@primeuix/themes/aura";
import Lara from "@primeuix/themes/lara";
import Nora from "@primeuix/themes/nora";
import { computed, ref, watch, watchEffect } from "vue";
import BaseButton from "../../components/base/BaseButton.vue";
import BaseColorPicker from "../../components/base/BaseColorPicker.vue";
import BaseRadioButton from "../../components/base/BaseRadioButton.vue";
import BaseSelectButton from "../../components/base/BaseSelectButton.vue";
import { useBaseToast } from "../../composables/useBaseToast.js";
import { persistAppAppearance } from "../../composables/useAppSettings";
import { apiErrorDetail } from "../../services/api";
import { applyThemeFromLayoutConfig } from "../../themeBootstrap";
import {
  applyThemeFromConfig,
  buildPresetExtension,
  DEFAULT_PRIMARY_CUSTOM,
  DEFAULT_SURFACE_CUSTOM,
  PRIMARY_PRESETS,
  resolvePrimaryColor,
  resolveSurfacePalette,
  SURFACE_PRESETS,
} from "../../lib/themePalettes.js";

const { layoutConfig, isDarkTheme, changeMenuMode } = useLayout();

const toast = useBaseToast();
const saving = ref(false);

const presets = {
  Aura,
  Lara,
  Nora,
};
const presetOptions = ref(Object.keys(presets));
const preset = ref(layoutConfig.preset);
const themeOptions = ref([
  { name: "Light", value: false },
  { name: "Dark", value: true },
]);
const menuThemeOptions = computed(() => {
  if (isDarkTheme.value) {
    return [
      { name: "Dark", value: "dark" },
      { name: "Primary", value: "primary" },
    ];
  } else {
    return [
      { name: "Light", value: "light" },
      { name: "Dark", value: "dark" },
      { name: "Primary", value: "primary" },
    ];
  }
});
const cardStyleOptions = ref([
  { name: "Transparent", value: "transparent" },
  { name: "Filled", value: "filled" },
]);
const darkTheme = ref(layoutConfig.darkTheme);
const menuMode = ref(layoutConfig.menuMode);

const primaryColors = ref(PRIMARY_PRESETS);
const surfaces = ref(SURFACE_PRESETS);

const customPrimaryHex = ref(
  layoutConfig.primaryCustom || DEFAULT_PRIMARY_CUSTOM,
);
const customSurfaceHex = ref(
  layoutConfig.surfaceCustom || DEFAULT_SURFACE_CUSTOM,
);

watchEffect(() => {
  preset.value = layoutConfig.preset;
  darkTheme.value = layoutConfig.darkTheme;
  menuMode.value = layoutConfig.menuMode;
  customPrimaryHex.value =
    layoutConfig.primaryCustom || DEFAULT_PRIMARY_CUSTOM;
  customSurfaceHex.value =
    layoutConfig.surfaceCustom || DEFAULT_SURFACE_CUSTOM;
});

const menuTheme = computed(() => layoutConfig.menuTheme);
const cardStyle = computed(() => layoutConfig.cardStyle);

const customPrimaryPreview = computed(
  () => resolvePrimaryColor("custom", customPrimaryHex.value).palette["500"],
);
const customSurfacePreview = computed(
  () => resolveSurfacePalette("custom", customSurfaceHex.value)["500"],
);

function onDarkThemeChange(val) {
  const apply = () => {
    layoutConfig.darkTheme = val;
    darkTheme.value = val;
    document.documentElement.classList.toggle("app-dark", Boolean(val));
  };

  if (typeof document !== "undefined" && document.startViewTransition) {
    document.startViewTransition(apply);
  } else {
    apply();
  }
}

async function saveAppearanceToServer() {
  saving.value = true;
  try {
    await persistAppAppearance();
    applyThemeFromLayoutConfig();
    toast.add({
      severity: "success",
      summary: "Saved",
      detail: "Theme and layout apply for everyone on this instance.",
      life: 3500,
    });
  } catch (error) {
    toast.add({
      severity: "error",
      summary: "Could not save",
      detail: apiErrorDetail(error),
      life: 6500,
    });
  } finally {
    saving.value = false;
  }
}

function updateColors(type, color) {
  if (type === "primary") {
    layoutConfig.primary = color.name;
  } else if (type === "surface") {
    layoutConfig.surface = color.name;
  }

  applyTheme(type, color);
}

function onCustomPrimaryChange(hex) {
  layoutConfig.primaryCustom = hex;
  layoutConfig.primary = "custom";
  customPrimaryHex.value = hex;
  applyThemeFromConfig(layoutConfig);
}

function onCustomSurfaceChange(hex) {
  layoutConfig.surfaceCustom = hex;
  layoutConfig.surface = "custom";
  customSurfaceHex.value = hex;
  applyThemeFromConfig(layoutConfig);
}

function applyTheme(type, color) {
  if (type === "primary") {
    updatePreset(getPresetExt());
  } else if (type === "surface") {
    updateSurfacePalette(color.palette);
  }
}

function onPresetChange() {
  layoutConfig.preset = preset.value;
  const presetValue = presets[preset.value];
  const surfacePalette = resolveSurfacePalette(
    layoutConfig.surface,
    layoutConfig.surfaceCustom,
  );

  $t()
    .preset(presetValue)
    .preset(getPresetExt())
    .surfacePalette(surfacePalette)
    .use({ useDefaultOptions: true });
}

function onMenuThemeChange(event) {
  layoutConfig.menuTheme = event.value;
}

function onCardStyleChange(event) {
  layoutConfig.cardStyle = event.value;
}

function getPresetExt() {
  return buildPresetExtension(layoutConfig.primary, layoutConfig.primaryCustom);
}

watch(isDarkTheme, (newValue) => {
  if (newValue && menuTheme.value === "light") {
    layoutConfig.menuTheme = "dark";
  }
});
</script>

<template>
  <div class="maestro-appearance-settings flex flex-col gap-6">
    <div>
      <h2 class="title-h6 text-surface-900 dark:text-surface-0 mb-1">
        Theme &amp; layout
      </h2>
      <p class="body-small text-surface-600 dark:text-surface-400">
        PrimeVue preset, colors, and application shell. Adjust below, then click
        <strong class="font-semibold">Save appearance</strong> so everyone sees
        the same theme on this instance.
      </p>
    </div>

    <div class="flex flex-col gap-6">
      <div>
        <span class="text-lg text-muted-color font-semibold">Primary</span>
        <div class="pt-2 flex gap-2 flex-wrap">
          <button
            v-for="primaryColor of primaryColors"
            :key="primaryColor.name"
            type="button"
            class="w-6 h-6 cursor-pointer hover:shadow-lg rounded duration-150 flex items-center justify-center"
            :style="{
              backgroundColor: `${primaryColor.name === 'noir' ? 'var(--text-color)' : primaryColor.palette['500']}`,
            }"
            @click="updateColors('primary', primaryColor)"
          >
            <i
              v-if="primaryColor.name === layoutConfig.primary"
              class="pi pi-check text-white"
            />
          </button>
          <button
            type="button"
            class="w-6 h-6 cursor-pointer hover:shadow-lg rounded duration-150 flex items-center justify-center ring-1 ring-surface-300 dark:ring-surface-600"
            :style="{ backgroundColor: customPrimaryPreview }"
            title="Custom primary"
            @click="onCustomPrimaryChange(customPrimaryHex)"
          >
            <i
              v-if="layoutConfig.primary === 'custom'"
              class="pi pi-check text-white"
            />
          </button>
        </div>
        <div class="pt-4 max-w-md">
          <BaseColorPicker
            v-model="customPrimaryHex"
            label="Custom primary"
            description="Pick a base color; shades are generated automatically."
            @change="onCustomPrimaryChange"
          />
        </div>
      </div>

      <div>
        <span class="text-lg text-muted-color font-semibold">Surface</span>
        <div class="pt-2 flex gap-2 flex-wrap">
          <button
            v-for="surface of surfaces"
            :key="surface.name"
            type="button"
            class="w-6 h-6 cursor-pointer hover:shadow-lg rounded duration-150 flex items-center justify-center"
            :style="{ backgroundColor: `${surface.palette['500']}` }"
            @click="updateColors('surface', surface)"
          >
            <i
              v-if="
                layoutConfig.surface
                  ? layoutConfig.surface === surface.name
                  : isDarkTheme
                    ? surface.name === 'zinc'
                    : surface.name === 'slate'
              "
              class="pi pi-check text-white"
            />
          </button>
          <button
            type="button"
            class="w-6 h-6 cursor-pointer hover:shadow-lg rounded duration-150 flex items-center justify-center ring-1 ring-surface-300 dark:ring-surface-600"
            :style="{ backgroundColor: customSurfacePreview }"
            title="Custom surface"
            @click="onCustomSurfaceChange(customSurfaceHex)"
          >
            <i
              v-if="layoutConfig.surface === 'custom'"
              class="pi pi-check text-white"
            />
          </button>
        </div>
        <div class="pt-4 max-w-md">
          <BaseColorPicker
            v-model="customSurfaceHex"
            label="Custom surface"
            description="Pick the mid-tone neutral (shade 500); lighter and darker surfaces are derived automatically."
            @change="onCustomSurfaceChange"
          />
        </div>
      </div>

      <div>
        <div class="flex flex-col gap-2">
          <span class="text-lg text-muted-color font-semibold">Presets</span>
          <BaseSelectButton
            v-model="preset"
            :options="presetOptions"
            :allow-empty="false"
            @change="onPresetChange"
          />
        </div>
      </div>

      <div>
        <div class="flex flex-col gap-2">
          <span class="text-lg text-muted-color font-semibold"
            >Color Scheme</span
          >
          <BaseSelectButton
            v-model="darkTheme"
            :options="themeOptions"
            option-label="name"
            option-value="value"
            :allow-empty="false"
            @update:model-value="onDarkThemeChange"
          />
        </div>
      </div>

      <div class="flex flex-col gap-2">
        <span class="text-lg text-muted-color font-semibold">Card Style</span>
        <BaseSelectButton
          :model-value="cardStyle"
          :options="cardStyleOptions"
          :allow-empty="false"
          option-label="name"
          option-value="value"
          @change="onCardStyleChange"
        />
      </div>

      <div class="flex flex-col gap-2">
        <span class="text-lg text-muted-color font-semibold">Menu Theme</span>
        <BaseSelectButton
          :model-value="menuTheme"
          :options="menuThemeOptions"
          :allow-empty="false"
          option-label="name"
          option-value="value"
          @change="onMenuThemeChange"
        />
      </div>

      <div>
        <div class="flex flex-col gap-2">
          <span class="text-lg text-muted-color font-semibold">Menu Type</span>
          <div class="flex flex-wrap flex-col gap-3">
            <div class="flex">
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="static"
                  input-id="static"
                  @update:model-value="changeMenuMode"
                />
                <label for="static">Static</label>
              </div>

              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="overlay"
                  input-id="overlay"
                  @update:model-value="changeMenuMode"
                />
                <label for="overlay">Overlay</label>
              </div>
            </div>
            <div class="flex">
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="slim"
                  input-id="slim"
                  @update:model-value="changeMenuMode"
                />
                <label for="slim">Slim</label>
              </div>
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="compact"
                  input-id="compact"
                  @update:model-value="changeMenuMode"
                />
                <label for="compact">Compact</label>
              </div>
            </div>
            <div class="flex">
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="reveal"
                  input-id="reveal"
                  @update:model-value="changeMenuMode"
                />
                <label for="reveal">Reveal</label>
              </div>
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="drawer"
                  input-id="drawer"
                  @update:model-value="changeMenuMode"
                />
                <label for="drawer">Drawer</label>
              </div>
            </div>
            <div class="flex">
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="horizontal"
                  input-id="horizontal"
                  @update:model-value="changeMenuMode"
                />
                <label for="horizontal">Horizontal</label>
              </div>
              <div class="flex items-center gap-2 w-6/12">
                <BaseRadioButton
                  v-model="menuMode"
                  name="menuMode"
                  value="maestro"
                  input-id="maestro"
                  @update:model-value="changeMenuMode"
                />
                <label for="maestro">Maestro</label>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="flex flex-wrap gap-3 pt-2 border-t border-surface-200 dark:border-surface-700">
        <BaseButton
          type="button"
          variant="primary"
          label="Save appearance"
          icon="save"
          :loading="saving"
          @click="saveAppearanceToServer"
        />
      </div>
    </div>
  </div>
</template>
