/**
 * Zustand store for the Page Organizer admin UI.
 *
 * Key invariants:
 * - Shared instances (same instanceId in both device arrays) are updated in
 *   BOTH arrays by `updateConfig` and `updateVisibility`.
 * - `unlinkForDevice` assigns a fresh `crypto.randomUUID()` to the targeted
 *   device's entry only; the other device's entry retains its original id.
 * - All updates use `structuredClone` to ensure immutability.
 */

import { create } from 'zustand';
import type { LayoutBody, LayoutModule } from '@/server/page-layout/types';

interface OrganizerState {
  body: LayoutBody;
  updatedAt: string | null;
  device: 'mobile' | 'desktop';
  selectedInstanceId: string | null;
  richTextEdit: { instanceId: string } | null;
  saving: 'idle' | 'saving' | 'saved' | 'error' | 'conflict';

  setDevice: (d: 'mobile' | 'desktop') => void;
  select: (id: string | null) => void;
  setRichTextEdit: (v: { instanceId: string } | null) => void;
  reorder: (device: 'mobile' | 'desktop', from: number, to: number) => void;
  add: (device: 'mobile' | 'desktop', at: number, mod: LayoutModule) => void;
  remove: (device: 'mobile' | 'desktop', instanceId: string) => void;
  updateConfig: (instanceId: string, config: unknown) => void;
  updateVisibility: (instanceId: string, v: LayoutModule['visibility']) => void;
  unlinkForDevice: (instanceId: string, device: 'mobile' | 'desktop') => void;
  hydrate: (body: LayoutBody, updatedAt: string | null) => void;
  setSaving: (s: OrganizerState['saving']) => void;
}

export const useOrganizer = create<OrganizerState>((set) => ({
  body: { mobile: [], desktop: [] },
  updatedAt: null,
  device: 'mobile',
  selectedInstanceId: null,
  richTextEdit: null,
  saving: 'idle',

  setDevice: (device) => set({ device }),

  select: (selectedInstanceId) => set({ selectedInstanceId }),

  setRichTextEdit: (richTextEdit) => set({ richTextEdit }),

  hydrate: (body, updatedAt) => set({ body, updatedAt, saving: 'idle' }),

  setSaving: (saving) => set({ saving }),

  reorder: (device, from, to) =>
    set((s) => {
      const next = structuredClone(s.body);
      const arr = next[device];
      const removed = arr.splice(from, 1);
      if (!removed[0]) return {};
      arr.splice(to, 0, removed[0]);
      return { body: next };
    }),

  add: (device, at, mod) =>
    set((s) => {
      const next = structuredClone(s.body);
      next[device].splice(at, 0, mod);
      return { body: next };
    }),

  remove: (device, instanceId) =>
    set((s) => {
      const next = structuredClone(s.body);
      next[device] = next[device].filter((m) => m.instanceId !== instanceId);
      return { body: next };
    }),

  updateConfig: (instanceId, config) =>
    set((s) => {
      const next = structuredClone(s.body);
      for (const d of ['mobile', 'desktop'] as const) {
        next[d] = next[d].map((m) => (m.instanceId === instanceId ? { ...m, config } : m));
      }
      return { body: next };
    }),

  updateVisibility: (instanceId, visibility) =>
    set((s) => {
      const next = structuredClone(s.body);
      for (const d of ['mobile', 'desktop'] as const) {
        next[d] = next[d].map((m) => (m.instanceId === instanceId ? { ...m, visibility } : m));
      }
      return { body: next };
    }),

  unlinkForDevice: (instanceId, device) =>
    set((s) => {
      const next = structuredClone(s.body);
      const target = next[device].find((m) => m.instanceId === instanceId);
      if (!target) return {};
      target.instanceId = crypto.randomUUID();
      return { body: next, selectedInstanceId: target.instanceId };
    }),
}));
