<template>
  <Head title="Start" />
  <div class="min-h-screen bg-gradient-to-br from-slate-100 via-white to-slate-200 text-slate-900 transition-colors duration-500 dark:from-slate-950 dark:via-slate-900 dark:to-slate-950 dark:text-slate-100">
    <div class="mx-auto flex w-full max-w-7xl flex-col gap-6 px-2 py-8 sm:px-4 lg:px-6">
      <header class="rounded-3xl border border-slate-200 bg-white/90 p-6 text-slate-900 shadow-2xl backdrop-blur transition-colors duration-300 dark:border-white/10 dark:bg-white/5 dark:text-white">
        <div class="flex flex-wrap items-start justify-between gap-6">
          <div>
            <p class="text-xs uppercase tracking-[0.35em] text-slate-500 dark:text-slate-400">Live Gallery</p>
            <h1 class="mt-1 text-3xl font-semibold text-slate-900 dark:text-white sm:text-4xl">
              {{ props.galleryHeading }}
            </h1>
          </div>
          <div class="flex flex-wrap items-center gap-3">
            <button
              type="button"
              class="inline-flex items-center gap-2 rounded-full border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-900 shadow-sm transition hover:border-emerald-400 hover:text-emerald-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400 disabled:opacity-60 dark:border-white/20 dark:bg-white/10 dark:text-white dark:hover:text-emerald-200"
              @click="handleManualRefresh"
              :disabled="isRefreshing"
            >
              <font-awesome-icon :icon="['fas', 'arrows-rotate']" class="h-4 w-4" :class="{ 'animate-spin': isRefreshing }" />
              <span>{{ isRefreshing ? 'Aktualisiere…' : 'Jetzt aktualisieren' }}</span>
            </button>
            <button
              type="button"
              class="inline-flex items-center gap-2 rounded-full border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-900 shadow-sm transition hover:border-cyan-400 hover:text-cyan-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-400 dark:border-white/10 dark:bg-white/5 dark:text-white dark:hover:text-cyan-200"
              @click="toggleTheme"
            >
              <font-awesome-icon
                :icon="currentTheme === 'light' ? ['fas', 'moon'] : ['fas', 'sun']"
                class="h-4 w-4"
              />
              <span>{{ currentTheme === 'light' ? __('api.dark_mode') : __('api.light_mode') }}</span>
            </button>
            <div
              v-if="!effectiveAiAvailable"
              class="inline-flex items-center gap-2 rounded-full border border-rose-200 bg-rose-50 px-3 py-2 text-xs font-semibold uppercase tracking-[0.2em] text-rose-700 shadow-sm dark:border-rose-500/40 dark:bg-rose-500/10 dark:text-rose-200"
            >
              <span class="h-2 w-2 rounded-full bg-rose-500"></span>
              <span>AI offline</span>
            </div>
          </div>
        </div>
        <div class="mt-4 flex flex-wrap items-center gap-4 text-xs text-slate-500 dark:text-slate-300">
          <div class="inline-flex items-center gap-2 rounded-full bg-emerald-500/10 px-3 py-1 text-emerald-700 dark:text-emerald-200">
            <span class="h-2 w-2 rounded-full bg-emerald-500 animate-pulse"></span>
            Auto-Refresh · alle {{ refreshIntervalSeconds }}s
          </div>
          <div class="flex items-center gap-2">
            <span class="h-1.5 w-1.5 rounded-full bg-slate-400"></span>
            Letzte Synchronisierung: {{ formattedLastRefresh }}
          </div>
          <div class="flex items-center gap-2">
            <font-awesome-icon :icon="['fas', 'bars']" class="h-4 w-4" />
            Einfach über die Galerie wischen, um Seiten zu wechseln.
          </div>
        </div>
      </header>

      <section
        class="rounded-3xl border border-slate-200 bg-white/80 p-3 shadow-2xl backdrop-blur transition-colors duration-300 touch-pan-y dark:border-white/5 dark:bg-white/5 sm:p-4"
        @touchstart.passive="handleTouchStart"
        @touchmove.passive="handleTouchMove"
        @touchend="handleTouchEnd"
      >
        <GalleryGrid :images="paginatedImages" @imageTapped="showContextMenu" />
      </section>

      <Navigation :currentPage="currentPage" :totalPages="totalPages" @prevPage="prevPage" @nextPage="nextPage" />
    </div>

    <ImageContextMenu
      v-if="currentOverlayComponent === 'contextMenu' && selectedImage"
      :image="selectedImage"
      :allow-ai-styles="allowAiStyles"
      :show-print-button="showPrintButton"
      :gallery-slug="gallerySlug"
      :ai-available="effectiveAiAvailable"
      @close="closeOverlays"
      @print="printImage"
      @download="downloadImage"
      @styleSelected="applyStyle"
    />

    <StyledImageDisplay
      v-if="currentOverlayComponent === 'styledImageDisplay' && styledImage"
      :image="styledImage"
      @keep="keepStyledImage"
      @delete="deleteStyledImage"
    />

    <LoadingSpinner v-if="isLoading" :progress="processingProgress" />

    <PrintQuantityModal
      v-if="currentOverlayComponent === 'printQuantityModal' && selectedImage"
      @close="currentOverlayComponent = 'contextMenu'"
      @printConfirmed="handlePrintConfirmed"
      :maxCopies="maxCopiesSetting"
    />

    <div
      v-if="toastMessage"
      :class="['fixed bottom-6 right-6 z-[120] rounded-2xl px-4 py-3 text-sm font-semibold text-white shadow-2xl', toastBackground]"
    >
      {{ toastMessage }}
    </div>
  </div>
</template>

<script setup>
import { Head, usePage } from '@inertiajs/vue3';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import axios from 'axios';
import GalleryGrid from '../Components/GalleryGrid.vue';
import ImageContextMenu from '../Components/ImageContextMenu.vue';
import Navigation from '../Components/Navigation.vue';
import PrintQuantityModal from '../Components/PrintQuantityModal.vue';
import StyledImageDisplay from '../Components/StyledImageDisplay.vue';
import LoadingSpinner from '../Components/LoadingSpinner.vue';

const props = defineProps({
  galleryHeading: {
    type: String,
    default: 'Gallery',
  },
  gallery: {
    type: Object,
    default: () => ({}),
  },
  images: {
    type: Array,
    default: () => [],
  },
});

const page = usePage();
const settings = computed(() => page.props.settings || {});
const gallerySlug = computed(() => props.gallery?.slug || 'default');
const allowAiStyles = computed(() => props.gallery?.allow_ai_styles !== false);
const allowPrint = computed(() => props.gallery?.allow_print !== false);

const images = ref([]);
const imagesPerPage = 12;
const currentPage = ref(1);
const currentOverlayComponent = ref(null);
const selectedImage = ref(null);
const styledImage = ref(null);
const aiAvailable = ref(true);
const processingProgress = ref(0);
const isLoading = ref(false);
const currentTheme = ref('light');
const maxCopiesSetting = ref(10);
const isRefreshing = ref(false);
const lastRefreshedAt = ref(new Date());
const refreshIntervalMs = ref(5000);
const toastMessage = ref(null);
const toastVariant = ref('info');
let toastTimer = null;
let refreshTimer = null;
let aiStatusTimer = null;

const getImageIdentifier = (image) => image?.id ?? image?.image_id ?? null;

const extractFilenameFromHeader = (disposition) => {
  if (!disposition) {
    return null;
  }

  const filenameMatch = disposition.match(/filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i);
  if (!filenameMatch) {
    return null;
  }

  const encodedName = filenameMatch[1] || filenameMatch[2];
  try {
    return decodeURIComponent(encodedName);
  } catch (error) {
    return encodedName;
  }
};

watch(
  () => props.images,
  (newImages) => {
    if (Array.isArray(newImages)) {
      images.value = newImages;
      lastRefreshedAt.value = new Date();
    }
  },
  { immediate: true }
);

watch(
  () => images.value.length,
  () => {
    if (currentPage.value > totalPages.value) {
      currentPage.value = totalPages.value || 1;
    }
  }
);

const totalPages = computed(() => {
  return Math.max(1, Math.ceil(images.value.length / imagesPerPage));
});

const paginatedImages = computed(() => {
  const start = (currentPage.value - 1) * imagesPerPage;
  return images.value.slice(start, start + imagesPerPage);
});

const refreshIntervalSeconds = computed(() => Math.max(1, Math.round(refreshIntervalMs.value / 1000)));
const showPrintButton = computed(() => {
  return (settings.value.show_print_button ?? true) && allowPrint.value;
});
const effectiveAiAvailable = computed(() => allowAiStyles.value && aiAvailable.value);
const formattedLastRefresh = computed(() =>
  new Intl.DateTimeFormat(undefined, {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
  }).format(lastRefreshedAt.value)
);

const toastBackground = computed(() => {
  if (toastVariant.value === 'error') {
    return 'bg-rose-500/90';
  }
  if (toastVariant.value === 'success') {
    return 'bg-emerald-500/90';
  }
  return 'bg-slate-800/90';
});

const showToast = (message, variant = 'error') => {
  toastMessage.value = message;
  toastVariant.value = variant;
  if (toastTimer) {
    clearTimeout(toastTimer);
  }
  toastTimer = setTimeout(() => {
    toastMessage.value = null;
  }, 4000);
};

const applyTheme = (theme) => {
  document.documentElement.classList.remove('light', 'dark');
  document.documentElement.classList.add(theme);
  localStorage.setItem('theme', theme);
  currentTheme.value = theme;
};

const toggleTheme = () => {
  const newTheme = currentTheme.value === 'light' ? 'dark' : 'light';
  applyTheme(newTheme);
};

const checkAiStatus = () => {
  if (!allowAiStyles.value) {
    aiAvailable.value = false;
    return;
  }

  axios
    .get('/api/ai-status', {
      params: { gallery: gallerySlug.value },
    })
    .then((response) => {
      aiAvailable.value = response.data.some((provider) => provider.available);
    })
    .catch((error) => {
      console.error('Error checking AI status:', error);
      aiAvailable.value = false;
    });
};

const closeOverlays = () => {
  currentOverlayComponent.value = null;
  selectedImage.value = null;
};

const fetchImages = (options = { silent: false }) => {
  if (!options.silent) {
    isRefreshing.value = true;
  }

  axios
    .get('/api/images', {
      params: { gallery: gallerySlug.value },
    })
    .then((response) => {
      if (Array.isArray(response.data)) {
        images.value = response.data;
        lastRefreshedAt.value = new Date();
      }
    })
    .catch((error) => {
      console.error('Error fetching images:', error);
      showToast('Die Galerie konnte nicht aktualisiert werden.', 'error');
    })
    .finally(() => {
      if (!options.silent) {
        isRefreshing.value = false;
      }
    });
};

const startAutoRefresh = (intervalMs) => {
  refreshIntervalMs.value = intervalMs;
  if (refreshTimer) {
    clearInterval(refreshTimer);
  }
  refreshTimer = setInterval(() => fetchImages({ silent: true }), intervalMs);
};

const handleManualRefresh = () => {
  fetchImages({ silent: false });
};

const showContextMenu = (image) => {
  selectedImage.value = image;
  currentOverlayComponent.value = 'contextMenu';
};

const printImage = () => {
  if (!selectedImage.value || !showPrintButton.value) {
    return;
  }
  currentOverlayComponent.value = 'printQuantityModal';
};

const downloadImage = (imageParam = null) => {
  const image = imageParam || selectedImage.value;
  if (!image) {
    return;
  }

  showToast('Download wird vorbereitet…', 'info');

  axios
    .post(
      '/api/download-image',
      { image_path: image.path, gallery: gallerySlug.value },
      { responseType: 'blob' }
    )
    .then((response) => {
      const blob = new Blob([response.data]);
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      const disposition = response.headers?.['content-disposition'];
      const filenameFromHeader = extractFilenameFromHeader(disposition);
      const fallbackName = image.name || `stylegallery_${new Date().toISOString().replace(/[:.]/g, '-')}`;

      link.href = url;
      link.download = filenameFromHeader || fallbackName;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);
      showToast('Download gestartet!', 'success');
    })
    .catch((error) => {
      console.error('Error downloading image:', error);
      showToast(error.response?.data?.error || 'Download fehlgeschlagen.', 'error');
    });
};

const handlePrintConfirmed = (quantity) => {
  const identifier = getImageIdentifier(selectedImage.value);
  if (!identifier) {
    showToast('Kein Bild ausgewählt.', 'error');
    return;
  }

  axios
    .post('/api/print-image', {
      image_id: identifier,
      image_path: selectedImage.value.path,
      quantity,
      gallery: gallerySlug.value,
    })
    .then((response) => {
      console.log('Print request sent successfully:', response.data);
      showToast('Druckauftrag wurde übermittelt.', 'success');
    })
    .catch((error) => {
      console.error('Error sending print request:', error);
      showToast(error.response?.data?.error || 'Druckauftrag fehlgeschlagen.', 'error');
    })
    .finally(() => {
      currentOverlayComponent.value = null;
      selectedImage.value = null;
    });
};

const applyStyle = (style, imageId) => {
  if (!allowAiStyles.value) {
    showToast('Stilwechsel ist für diese Galerie deaktiviert.', 'error');
    return;
  }

  const targetImageId = imageId ?? getImageIdentifier(selectedImage.value);
  if (!targetImageId) {
    showToast('Kein Bild ausgewählt.', 'error');
    return;
  }

  console.log('Applying style:', style.title, 'to image:', targetImageId);
  currentOverlayComponent.value = null;
  isLoading.value = true;
  processingProgress.value = 0;

  axios
    .post('/api/images/style-change', {
      image_id: targetImageId,
      style_id: style.id,
      gallery: gallerySlug.value,
    })
    .then((response) => {
      const promptId = response.data.prompt_id;
      const plugin = response.data.plugin;

      if (plugin === 'ComfyUi') {
        axios
          .get('/api/comfyui-url', {
            params: { style_id: style.id, gallery: gallerySlug.value },
          })
          .then((comfyResponse) => {
            const comfyUiBaseUrl = comfyResponse.data.comfyui_url;
            const wsUrl = `ws://${new URL(comfyUiBaseUrl).host}/ws`;
            const ws = new WebSocket(wsUrl);

            ws.onopen = () => {
              ws.onmessage = (event) => {
                const message = JSON.parse(event.data);
                if (message.type === 'progress') {
                  const { value, max } = message.data;
                  const progress = max > 0 ? (value / max) * 100 : 0;
                  if (message.data.prompt_id === promptId) {
                    processingProgress.value = progress;

                    if (processingProgress.value >= 100) {
                      axios
                        .get(`/api/images/fetch-styled/${promptId}`, {
                          params: { gallery: gallerySlug.value },
                        })
                        .then((imageResponse) => {
                          styledImage.value = imageResponse.data.styled_image;
                          currentOverlayComponent.value = 'styledImageDisplay';
                          fetchImages({ silent: true });
                        })
                        .catch((imageError) => {
                          console.error('Frontend: Error fetching styled image:', imageError.response?.data?.error || imageError.message);
                          showToast(imageError.response?.data?.error || 'Failed to fetch styled image.', 'error');
                        })
                        .finally(() => {
                          isLoading.value = false;
                          processingProgress.value = 0;
                          ws.close();
                        });
                    }
                  }
                }
              };
            };

            ws.onerror = (error) => {
              console.error('WebSocket error:', error);
              showToast('WebSocket connection error.', 'error');
              isLoading.value = false;
              processingProgress.value = 0;
            };

            ws.onclose = () => {
              console.log('WebSocket closed.');
            };
          })
          .catch((error) => {
            console.error('Error fetching ComfyUI URL:', error);
            showToast(error.response?.data?.error || 'Failed to get ComfyUI URL.', 'error');
            isLoading.value = false;
          });
      } else {
        const pollForStyledImage = () => {
          axios
            .get(`/api/images/fetch-styled/${promptId}`, {
              params: { gallery: gallerySlug.value },
            })
            .then((imageResponse) => {
              styledImage.value = imageResponse.data.styled_image;
              currentOverlayComponent.value = 'styledImageDisplay';
              fetchImages({ silent: true });
              isLoading.value = false;
              processingProgress.value = 0;
            })
            .catch((imageError) => {
              if (imageError.response?.status === 404) {
                if (imageError.response?.data?.progress !== undefined) {
                  processingProgress.value = imageError.response.data.progress;
                }
                setTimeout(pollForStyledImage, 2000);
              } else {
                showToast(imageError.response?.data?.error || 'Failed to fetch styled image.', 'error');
                isLoading.value = false;
                processingProgress.value = 0;
              }
            });
        };

        pollForStyledImage();
      }
    })
    .catch((error) => {
      console.error('Error applying style:', error);
      showToast(error.response?.data?.error || 'Failed to apply style.', 'error');
      isLoading.value = false;
      processingProgress.value = 0;
    });
};

const keepStyledImage = () => {
  currentOverlayComponent.value = null;
  styledImage.value = null;
};

const deleteStyledImage = () => {
  if (!styledImage.value?.id) {
    currentOverlayComponent.value = null;
    styledImage.value = null;
    return;
  }

  axios
    .delete(`/api/images/${styledImage.value.id}/styled`, {
      params: { gallery: gallerySlug.value },
    })
    .then(() => {
      showToast('Bild gelöscht.', 'success');
      fetchImages({ silent: true });
    })
    .catch((error) => {
      console.error('Error deleting styled image:', error);
      showToast(error.response?.data?.error || 'Bild konnte nicht gelöscht werden.', 'error');
    })
    .finally(() => {
      currentOverlayComponent.value = null;
      styledImage.value = null;
    });
};

const prevPage = () => {
  if (currentPage.value > 1) {
    currentPage.value--;
  }
};

const nextPage = () => {
  if (currentPage.value < totalPages.value) {
    currentPage.value++;
  }
};

const touchStartX = ref(0);
const touchCurrentX = ref(0);
const swipeThreshold = 60;

const handleTouchStart = (event) => {
  if (!event.touches.length) {
    return;
  }
  touchStartX.value = event.touches[0].clientX;
  touchCurrentX.value = touchStartX.value;
};

const handleTouchMove = (event) => {
  if (!event.touches.length) {
    return;
  }
  touchCurrentX.value = event.touches[0].clientX;
};

const handleTouchEnd = (event) => {
  const endX = event.changedTouches?.[0]?.clientX ?? touchCurrentX.value;
  const delta = endX - touchStartX.value;

  if (Math.abs(delta) > swipeThreshold) {
    if (delta < 0) {
      nextPage();
    } else {
      prevPage();
    }
  }
};

onMounted(() => {
  const savedTheme = localStorage.getItem('theme');
  if (savedTheme) {
    applyTheme(savedTheme);
  } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
    applyTheme('dark');
  } else {
    applyTheme('light');
  }

  axios
    .get('/api/image-refresh-interval', {
      params: { gallery: gallerySlug.value },
    })
    .then((response) => {
      startAutoRefresh(response.data.interval * 1000);
    })
    .catch((error) => {
      console.error('Error fetching image refresh interval:', error);
      startAutoRefresh(5000);
    });

  axios
    .get('/api/max-copies-setting', {
      params: { gallery: gallerySlug.value },
    })
    .then((response) => {
      maxCopiesSetting.value = response.data.max_copies;
    })
    .catch((error) => {
      console.error('Error fetching max copies setting:', error);
    });

  checkAiStatus();
  aiStatusTimer = setInterval(() => checkAiStatus(), 300000);
});

onUnmounted(() => {
  if (refreshTimer) {
    clearInterval(refreshTimer);
  }
  if (toastTimer) {
    clearTimeout(toastTimer);
  }
  if (aiStatusTimer) {
    clearInterval(aiStatusTimer);
  }
});
</script>
