<template>
  <Head title="Start" />
  <div class="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-slate-100">
    <div class="mx-auto flex w-full max-w-7xl flex-col gap-6 px-4 py-8 sm:px-6 lg:px-8">
      <header class="rounded-3xl border border-white/10 bg-white/5 p-6 shadow-2xl backdrop-blur">
        <div class="flex flex-wrap items-start justify-between gap-6">
          <div>
            <p class="text-xs uppercase tracking-[0.35em] text-slate-400">Live Gallery</p>
            <h1 class="mt-2 text-3xl font-semibold text-white sm:text-4xl">
              {{ props.galleryHeading }}
            </h1>
            <p class="mt-1 text-sm text-slate-400">Touch-friendly wall with the freshest images.</p>
          </div>
          <div class="flex flex-wrap items-center gap-3">
            <button
              type="button"
              class="inline-flex items-center gap-2 rounded-full border border-white/20 bg-white/10 px-4 py-2 text-sm font-semibold text-white transition hover:border-emerald-400 hover:text-emerald-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-400 disabled:opacity-60"
              @click="handleManualRefresh"
              :disabled="isRefreshing"
            >
              <svg
                class="h-4 w-4"
                :class="{ 'animate-spin': isRefreshing }"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="1.5"
              >
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M16.023 9.348h4.992V4.355m0 0-2.852 2.853A8.25 8.25 0 0 0 4.5 12c0 1.007.176 1.973.5 2.869m2.977 4.784H3v4.993m0 0 2.853-2.853A8.25 8.25 0 0 0 19.5 12c0-1.007-.176-1.973-.5-2.869"
                />
              </svg>
              <span>{{ isRefreshing ? 'Aktualisiere…' : 'Jetzt aktualisieren' }}</span>
            </button>
            <button
              type="button"
              class="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-cyan-300 hover:text-cyan-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-cyan-400"
              @click="toggleTheme"
            >
              <svg v-if="currentTheme === 'light'" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
                <path stroke-linecap="round" stroke-linejoin="round" d="M21.75 15A9.75 9.75 0 1 1 9 2.25 7.5 7.5 0 0 0 21.75 15Z" />
              </svg>
              <svg v-else class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
                <path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-3.773-4.227-1.591 1.591M5.25 12H3m4.227-3.773L5.636 6.636M12 8.25a3.75 3.75 0 1 0 0 7.5 3.75 3.75 0 0 0 0-7.5Z"
                />
              </svg>
              <span>{{ currentTheme === 'light' ? __('api.dark_mode') : __('api.light_mode') }}</span>
            </button>
          </div>
        </div>
        <div class="mt-4 flex flex-wrap items-center gap-4 text-xs text-slate-300">
          <div class="inline-flex items-center gap-2 rounded-full bg-emerald-400/10 px-3 py-1 text-emerald-200">
            <span class="h-2 w-2 rounded-full bg-emerald-400 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">
            <svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
              <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5h7.5m-9 5.25h10.5M6 15h12m-9 5.25h6" />
            </svg>
            Einfach über die Galerie wischen, um Seiten zu wechseln.
          </div>
        </div>
      </header>

      <section
        class="rounded-3xl border border-white/5 bg-white/5 p-4 shadow-2xl backdrop-blur touch-pan-y"
        @touchstart.passive="handleTouchStart"
        @touchmove.passive="handleTouchMove"
        @touchend="handleTouchEnd"
      >
        <GalleryGrid :images="paginatedImages" @imageTapped="showContextMenu" :translations="props.translations" />
      </section>

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

    <ImageContextMenu
      v-if="currentOverlayComponent === 'contextMenu' && selectedImage"
      :image="selectedImage"
      @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, router } 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',
  },
  translations: {
    type: Object,
    default: () => ({}),
  },
  images: {
    type: Array,
    default: () => [],
  },
});

const images = ref([]);
const imagesPerPage = 12;
const currentPage = ref(1);
const currentOverlayComponent = ref(null);
const selectedImage = ref(null);
const styledImage = ref(null);
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;

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

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 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 closeOverlays = () => {
  currentOverlayComponent.value = null;
  selectedImage.value = null;
};

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

  router.reload({
    only: ['images'],
    preserveScroll: true,
    onSuccess: (page) => {
      if (Array.isArray(page.props.images)) {
        images.value = page.props.images;
        lastRefreshedAt.value = new Date();
      }
    },
    onError: () => {
      showToast('Die Galerie konnte nicht aktualisiert werden.', 'error');
    },
    onFinish: () => {
      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) {
    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 },
      { responseType: 'blob' }
    )
    .then((response) => {
      const blob = new Blob([response.data]);
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = image.name || 'image';
      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,
    })
    .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) => {
  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,
    })
    .then((response) => {
      const promptId = response.data.prompt_id;
      const plugin = response.data.plugin;

      if (plugin === 'ComfyUi') {
        axios
          .get(`/api/comfyui-url?style_id=${style.id}`)
          .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}`)
                        .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}`)
            .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 = () => {
  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')
    .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')
    .then((response) => {
      maxCopiesSetting.value = response.data.max_copies;
    })
    .catch((error) => {
      console.error('Error fetching max copies setting:', error);
    });
});

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