import { useSyncExternalStore, useCallback } from "react";

export interface EditorTab {
  path: string;
  name: string;
  content: string;
  savedContent: string;
  language: string;
}

export interface SearchResult {
  filePath: string;
  fileName: string;
  lineNumber: number;
  lineContent: string;
  matchStart: number;
  matchEnd: number;
}

export interface EditorSettings {
  fontSize: number;
  fontFamily: string;
  tabSize: number;
  wordWrap: boolean;
  autoSave: boolean;
  theme: "dark" | "light";
  customCssPath: string | null;
}

interface EditorStore {
  tabs: EditorTab[];
  activeTabPath: string | null;
  workspacePath: string | null;
  sidebarVisible: boolean;
  terminalVisible: boolean;
  sidebarView: "files" | "search";
  searchQuery: string;
  searchResults: SearchResult[];
  searchCaseSensitive: boolean;
  searchRegex: boolean;
  splitEditorPath: string | null;
  recentWorkspaces: string[];
  fileTreeFilter: string;
  cursorLine: number;
  cursorCol: number;
  settings: EditorSettings;
}

const defaultSettings: EditorSettings = {
  fontSize: 14,
  fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
  tabSize: 2,
  wordWrap: false,
  autoSave: false,
  theme: "dark",
  customCssPath: null,
};

function loadSettings(): EditorSettings {
  try {
    const stored = localStorage.getItem("editor-settings");
    if (stored) return { ...defaultSettings, ...JSON.parse(stored) };
  } catch { /* ignore */ }
  return defaultSettings;
}

function loadRecentWorkspaces(): string[] {
  try {
    const stored = localStorage.getItem("recent-workspaces");
    if (stored) return JSON.parse(stored);
  } catch { /* ignore */ }
  return [];
}

let state: EditorStore = {
  tabs: [],
  activeTabPath: null,
  workspacePath: null,
  sidebarVisible: true,
  terminalVisible: false,
  sidebarView: "files",
  searchQuery: "",
  searchResults: [],
  searchCaseSensitive: false,
  searchRegex: false,
  splitEditorPath: null,
  recentWorkspaces: loadRecentWorkspaces(),
  fileTreeFilter: "",
  cursorLine: 1,
  cursorCol: 1,
  settings: loadSettings(),
};

const listeners = new Set<() => void>();

function emit() {
  listeners.forEach((l) => l());
}

function getSnapshot() {
  return state;
}

function subscribe(listener: () => void) {
  listeners.add(listener);
  return () => listeners.delete(listener);
}

export function useStore() {
  return useSyncExternalStore(subscribe, getSnapshot);
}

export function useStoreSelector<T>(selector: (s: EditorStore) => T): T {
  const select = useCallback(() => selector(getSnapshot()), [selector]);
  return useSyncExternalStore(subscribe, select);
}

export const actions = {
  openFile(path: string, name: string, content: string, language: string) {
    const existing = state.tabs.find((t) => t.path === path);
    if (existing) {
      state = { ...state, activeTabPath: path };
    } else {
      state = {
        ...state,
        tabs: [...state.tabs, { path, name, content, savedContent: content, language }],
        activeTabPath: path,
      };
    }
    emit();
  },

  closeTab(path: string) {
    const tabs = state.tabs.filter((t) => t.path !== path);
    let activeTabPath = state.activeTabPath;
    if (activeTabPath === path) {
      const idx = state.tabs.findIndex((t) => t.path === path);
      activeTabPath = tabs[Math.min(idx, tabs.length - 1)]?.path ?? null;
    }
    // Also close split if it was showing this file
    let splitEditorPath = state.splitEditorPath;
    if (splitEditorPath === path) {
      splitEditorPath = null;
    }
    state = { ...state, tabs, activeTabPath, splitEditorPath };
    emit();
  },

  setActiveTab(path: string) {
    state = { ...state, activeTabPath: path };
    emit();
  },

  updateContent(path: string, content: string) {
    state = {
      ...state,
      tabs: state.tabs.map((t) => (t.path === path ? { ...t, content } : t)),
    };
    emit();
  },

  markSaved(path: string) {
    state = {
      ...state,
      tabs: state.tabs.map((t) =>
        t.path === path ? { ...t, savedContent: t.content } : t
      ),
    };
    emit();
  },

  setWorkspace(path: string | null) {
    state = { ...state, workspacePath: path };
    if (path) {
      const recents = [path, ...state.recentWorkspaces.filter((w) => w !== path)].slice(0, 10);
      state = { ...state, recentWorkspaces: recents };
      localStorage.setItem("recent-workspaces", JSON.stringify(recents));
    }
    emit();
  },

  toggleSidebar() {
    state = { ...state, sidebarVisible: !state.sidebarVisible };
    emit();
  },

  toggleTerminal() {
    state = { ...state, terminalVisible: !state.terminalVisible };
    emit();
  },

  setSidebarView(view: "files" | "search") {
    state = { ...state, sidebarView: view, sidebarVisible: true };
    emit();
  },

  setSearchQuery(query: string) {
    state = { ...state, searchQuery: query };
    emit();
  },

  setSearchResults(results: SearchResult[]) {
    state = { ...state, searchResults: results };
    emit();
  },

  setSearchCaseSensitive(value: boolean) {
    state = { ...state, searchCaseSensitive: value };
    emit();
  },

  setSearchRegex(value: boolean) {
    state = { ...state, searchRegex: value };
    emit();
  },

  setSplitEditor(path: string | null) {
    state = { ...state, splitEditorPath: path };
    emit();
  },

  setFileTreeFilter(filter: string) {
    state = { ...state, fileTreeFilter: filter };
    emit();
  },

  reorderTabs(fromIndex: number, toIndex: number) {
    const tabs = [...state.tabs];
    const [moved] = tabs.splice(fromIndex, 1);
    tabs.splice(toIndex, 0, moved);
    state = { ...state, tabs };
    emit();
  },

  reloadFileContent(path: string, content: string) {
    state = {
      ...state,
      tabs: state.tabs.map((t) =>
        t.path === path ? { ...t, content, savedContent: content } : t
      ),
    };
    emit();
  },

  setCursor(line: number, col: number) {
    state = { ...state, cursorLine: line, cursorCol: col };
    emit();
  },

  updateTabLanguage(path: string, language: string) {
    state = {
      ...state,
      tabs: state.tabs.map((t) => (t.path === path ? { ...t, language } : t)),
    };
    emit();
  },

  updateSettings(partial: Partial<EditorSettings>) {
    const settings = { ...state.settings, ...partial };
    state = { ...state, settings };
    localStorage.setItem("editor-settings", JSON.stringify(settings));
    emit();
  },

  getState() {
    return state;
  },
};
