document.addEventListener('alpine:init', () => {
  Alpine.data('library', () => ({
    currentPath: '', parentPath: null, entries: [], selected: null,
    loading: false, playerLoading: false, playerLoadingCompact: false,
    error: '', playerController: null, viewMode: 'grid',
    infoOpen: false, infoLoading: false, infoError: '', diagnostics: null,
    previewFrames: {}, previewUrls: {}, previewStates: {}, previewTimers: {},
    previewActive: {}, previewImages: {}, previewGeneration: 0,

    init() {
      try { this.viewMode = localStorage.getItem('lan-play:view') || 'grid'; } catch (_) {}
      this.locationHandler = () => { this.restoreLocation(); };
      this.resizeHandler = () => { this.scheduleMarqueeCheck(); };
      window.addEventListener('popstate', this.locationHandler);
      window.addEventListener('resize', this.resizeHandler);
    },

    destroy() {
      this.stopAllPreviews();
      this.cancelPreviewLoads();
      window.removeEventListener('popstate', this.locationHandler);
      window.removeEventListener('resize', this.resizeHandler);
      if (this.marqueeFrame) window.cancelAnimationFrame(this.marqueeFrame);
      if (this.playerController) this.playerController.dispose();
    },

    async restoreLocation() {
      const location = window.LanPlayLocation.read();
      if (this.playerController) await this.playerController.stop();
      this.selected = null;
      await this.browse(location.path, false);
      if (location.play) {
        await this.play({
          path: location.play,
          name: window.LanPlayLocation.fileName(location.play),
          kind: 'media'
        }, false);
      }
    },

    async browse(path, updateLocation = true) {
      this.stopAllPreviews();
      this.cancelPreviewLoads();
      this.loading = true;
      this.error = '';
      try {
        const data = await window.LanPlayApi.browse(path);
        this.currentPath = data.path;
        this.parentPath = data.parent;
        this.entries = data.entries;
        if (updateLocation) window.LanPlayLocation.write(data.path, null, false);
        await this.$nextTick();
        this.preloadPreviews(data.entries);
        this.scheduleMarqueeCheck();
      } catch (error) { this.error = error.message; }
      finally { this.loading = false; }
    },

    async play(entry, updateLocation = true) {
      this.stopAllPreviews();
      this.enterFullscreen();
      this.error = '';
      this.selected = entry;
      this.playerLoading = true;
      if (updateLocation) window.LanPlayLocation.write(this.currentPath, entry.path, false);
      await this.$nextTick();
      if (!this.playerController) {
        this.playerController = new window.LanPlayPlayer(
          this.$refs.video,
          this.$refs.videoWrapper,
          (message) => { this.error = message; },
          (loading, compact = false) => {
            this.playerLoading = loading;
            this.playerLoadingCompact = loading && compact;
          },
          () => { this.playNext(); }
        );
      }
      this.playerController.setNextAvailable(Boolean(this.nextEntry()));
      try { await this.playerController.play(entry); }
      catch (error) { this.error = error.message; }
      finally {
        this.playerLoading = false;
        this.playerLoadingCompact = false;
      }
    },

    nextEntry() {
      if (!this.selected) return null;
      const media = this.entries.filter((entry) => entry.kind === 'media');
      const index = media.findIndex((entry) => entry.path === this.selected.path);
      return index >= 0 ? media[index + 1] || null : null;
    },

    async playNext() {
      const next = this.nextEntry();
      if (next) await this.play(next);
    },

    mediaTitle() {
      if (!this.selected || !this.selected.name) return '';
      return this.selected.name.replace(/\.[^.]+$/, '');
    },

    setViewMode(mode) {
      this.viewMode = mode === 'table' ? 'table' : 'grid';
      try { localStorage.setItem('lan-play:view', this.viewMode); } catch (_) {}
      this.$nextTick(() => this.scheduleMarqueeCheck());
    },

    scheduleMarqueeCheck() {
      if (this.marqueeFrame) window.cancelAnimationFrame(this.marqueeFrame);
      this.marqueeFrame = window.requestAnimationFrame(() => {
        this.marqueeFrame = null;
        document.querySelectorAll('.entry-name').forEach((container) => {
          if (container.clientWidth <= 0) return;
          const text = container.querySelector('.entry-name-track');
          container.classList.toggle('is-overflowing', Boolean(text) && text.scrollWidth > container.clientWidth + 1);
        });
      });
    },

    openEntry(entry) {
      return entry.kind === 'directory' ? this.browse(entry.path) : this.play(entry);
    },

    async openInfo() {
      this.infoOpen = true;
      this.infoLoading = true;
      this.infoError = '';
      try {
        const server = await window.LanPlayApi.info();
        let dashVersion = 'Unknown';
        try { dashVersion = dashjs.MediaPlayer().create().getVersion(); } catch (_) {}
        this.diagnostics = {
          ...server,
          interface: '20',
          dashjs: dashVersion,
          browser: navigator.userAgent,
          display: `${window.screen.width}×${window.screen.height} @ ${window.devicePixelRatio || 1}x`,
          fullscreen: Boolean(document.documentElement.requestFullscreen || document.documentElement.webkitRequestFullscreen),
          mediaSource: 'MediaSource' in window
        };
      } catch (error) {
        this.infoError = error.message;
      } finally {
        this.infoLoading = false;
      }
    },

    closeInfo() {
      this.infoOpen = false;
    },

    previewStyle(entry) {
      if (this.previewStates[entry.path] !== 'ready') return '';
      const url = this.previewUrls[entry.path];
      if (!url) return '';
      const frame = this.previewFrames[entry.path] || 0;
      const column = frame % 5;
      const row = Math.floor(frame / 5);
      return `background-image:url("${url}");background-position:${column * 25}% ${row * 100}%`;
    },

    startPreview(entry) {
      if (!entry || entry.kind !== 'media') return;
      this.previewActive[entry.path] = true;
      this.stopPreview(entry);
      this.previewActive[entry.path] = true;
      if (this.previewStates[entry.path] !== 'ready') return;
      this.previewFrames[entry.path] = 0;
      this.previewTimers[entry.path] = window.setInterval(() => {
        this.previewFrames[entry.path] = ((this.previewFrames[entry.path] || 0) + 1) % 10;
      }, 500);
    },

    stopPreview(entry) {
      if (!entry) return;
      this.previewActive[entry.path] = false;
      const timer = this.previewTimers[entry.path];
      if (timer) window.clearInterval(timer);
      delete this.previewTimers[entry.path];
      this.previewFrames[entry.path] = 0;
    },

    stopAllPreviews() {
      Object.values(this.previewTimers).forEach((timer) => window.clearInterval(timer));
      this.previewTimers = {};
      this.previewActive = {};
    },

    preloadPreviews(entries) {
      const generation = this.previewGeneration;
      entries.filter((entry) => entry.kind === 'media').forEach((entry) => {
        const path = entry.path;
        const url = `/api/preview?path=${encodeURIComponent(path)}`;
        const image = new Image();
        this.previewUrls[path] = url;
        this.previewStates[path] = 'loading';
        this.previewImages[path] = image;
        image.onload = () => {
          if (generation !== this.previewGeneration) return;
          this.previewStates[path] = 'ready';
          delete this.previewImages[path];
          if (this.previewActive[path]) this.startPreview(entry);
        };
        image.onerror = () => {
          if (generation !== this.previewGeneration) return;
          this.previewStates[path] = 'error';
          delete this.previewImages[path];
        };
        image.src = url;
      });
    },

    cancelPreviewLoads() {
      this.previewGeneration += 1;
      Object.values(this.previewImages).forEach((image) => {
        image.onload = null;
        image.onerror = null;
        image.src = '';
      });
      this.previewImages = {};
      this.previewFrames = {};
      this.previewUrls = {};
      this.previewStates = {};
    },

    enterFullscreen() {
      if (document.fullscreenElement || document.webkitFullscreenElement) return;
      const root = document.documentElement;
      const request = root.requestFullscreen || root.webkitRequestFullscreen;
      if (request) {
        try {
          const result = request.call(root);
          if (result && result.catch) result.catch(() => {});
        } catch (_) {}
      }
    },

    exitFullscreen() {
      if (!document.fullscreenElement && !document.webkitFullscreenElement) return;
      const exit = document.exitFullscreen || document.webkitExitFullscreen;
      if (exit) {
        try {
          const result = exit.call(document);
          if (result && result.catch) result.catch(() => {});
        } catch (_) {}
      }
    },

    async closePlayer(updateLocation = true) {
      this.exitFullscreen();
      this.selected = null;
      this.playerLoading = false;
      this.playerLoadingCompact = false;
      if (updateLocation) window.LanPlayLocation.write(this.currentPath, null, false);
      await this.$nextTick();
      if (this.playerController) this.playerController.stop();
    }
  }));
});
