/**
 * Live Preview Store
 * Manages preview state, console output, and runtime
 */

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import {
  PreviewScene,
  PreviewInstance,
  ConsoleOutput,
  PreviewSettings,
  DEFAULT_PREVIEW_SETTINGS,
  createDefaultScene,
  convertToPreviewInstance,
} from '@/lib/preview/types';
import { createLuaRuntime, LuaRuntime, LuaRuntimeOutput } from '@/lib/preview/lua-runtime';

interface PreviewState {
  // Scene
  scene: PreviewScene;

  // Runtime
  isRunning: boolean;
  isPaused: boolean;
  runtime: LuaRuntime | null;

  // Console
  consoleOutputs: ConsoleOutput[];
  maxConsoleOutputs: number;

  // Settings
  settings: PreviewSettings;

  // Code
  currentCode: string;

  // Actions
  setScene: (scene: PreviewScene) => void;
  addInstance: (instance: PreviewInstance) => void;
  removeInstance: (id: string) => void;
  updateInstance: (id: string, updates: Partial<PreviewInstance>) => void;
  clearInstances: () => void;

  // Runtime actions
  runScript: (code: string) => Promise<void>;
  stopScript: () => void;
  pauseScript: () => void;
  resumeScript: () => void;
  resetScene: () => void;

  // Console actions
  addConsoleOutput: (output: Omit<ConsoleOutput, 'id'>) => void;
  clearConsole: () => void;

  // Settings actions
  updateSettings: (settings: Partial<PreviewSettings>) => void;
}

let outputIdCounter = 0;

export const usePreviewStore = create<PreviewState>()(
  persist(
    (set, get) => ({
      // Initial state
      scene: createDefaultScene(),
      isRunning: false,
      isPaused: false,
      runtime: null,
      consoleOutputs: [],
      maxConsoleOutputs: 1000,
      settings: DEFAULT_PREVIEW_SETTINGS,
      currentCode: '',

      // Scene actions
      setScene: (scene) => set({ scene }),

      addInstance: (instance) =>
        set((state) => ({
          scene: {
            ...state.scene,
            instances: [...state.scene.instances, instance],
          },
        })),

      removeInstance: (id) =>
        set((state) => ({
          scene: {
            ...state.scene,
            instances: state.scene.instances.filter((i) => i.id !== id),
          },
        })),

      updateInstance: (id, updates) =>
        set((state) => ({
          scene: {
            ...state.scene,
            instances: state.scene.instances.map((i) =>
              i.id === id ? { ...i, ...updates } : i
            ),
          },
        })),

      clearInstances: () =>
        set((state) => ({
          scene: {
            ...state.scene,
            instances: state.scene.instances.filter(
              (i) => i.id === 'baseplate' || i.id === 'spawnlocation'
            ),
          },
        })),

      // Runtime actions
      runScript: async (code: string) => {
        const { stopScript, addConsoleOutput } = get();

        // Stop any existing script
        stopScript();

        // Create new runtime
        const runtime = createLuaRuntime();

        // Set up output listener
        runtime.onOutput((output: LuaRuntimeOutput) => {
          addConsoleOutput({
            type: output.type,
            message: output.message,
            timestamp: output.timestamp,
          });
        });

        // Set up instance listener
        runtime.onInstanceUpdate((instances) => {
          set((state) => {
            const baseInstances = state.scene.instances.filter(
              (i) => i.id === 'baseplate' || i.id === 'spawnlocation'
            );

            const newInstances = instances.map((inst, idx) =>
              convertToPreviewInstance(inst, `runtime-${idx}`)
            );

            return {
              scene: {
                ...state.scene,
                instances: [...baseInstances, ...newInstances],
              },
            };
          });
        });

        set({ runtime, isRunning: true, isPaused: false, currentCode: code });

        // Execute script
        await runtime.execute(code);

        set({ isRunning: false });
      },

      stopScript: () => {
        const { runtime } = get();
        if (runtime) {
          runtime.stop();
        }
        set({ runtime: null, isRunning: false, isPaused: false });
      },

      pauseScript: () => {
        set({ isPaused: true });
      },

      resumeScript: () => {
        set({ isPaused: false });
      },

      resetScene: () => {
        const { stopScript, clearConsole } = get();
        stopScript();
        clearConsole();
        set({
          scene: createDefaultScene(),
          currentCode: '',
        });
      },

      // Console actions
      addConsoleOutput: (output) =>
        set((state) => {
          const newOutput: ConsoleOutput = {
            ...output,
            id: `output-${outputIdCounter++}`,
          };

          let outputs = [...state.consoleOutputs, newOutput];

          // Trim if over limit
          if (outputs.length > state.maxConsoleOutputs) {
            outputs = outputs.slice(-state.maxConsoleOutputs);
          }

          return { consoleOutputs: outputs };
        }),

      clearConsole: () => set({ consoleOutputs: [] }),

      // Settings actions
      updateSettings: (newSettings) =>
        set((state) => ({
          settings: { ...state.settings, ...newSettings },
        })),
    }),
    {
      name: 'aethex-preview',
      partialize: (state) => ({
        settings: state.settings,
      }),
    }
  )
);
