import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { DeleteReference, ConfirmDeleteDetails } from '../components/ConfirmDeleteModal';
import type { SidebarView } from '../navigation/sidebarViewRegistry';
import type {
  ProjectData,
  PostData,
  MediaData,
  TaskProgress,
} from '../../main/shared/electronApi';

// Storage key for persisted state
const STORAGE_KEY = 'bds-app-state';

// Tab types
export type TabType = 'post' | 'media' | 'settings' | 'style' | 'tags' | 'chat' | 'import' | 'menu-editor' | 'metadata-diff' | 'git-diff' | 'documentation' | 'api-documentation' | 'site-validation' | 'scripts' | 'templates';

export interface Tab {
  type: TabType;
  id: string;
  isTransient: boolean;
}

export interface TabState {
  tabs: Tab[];
  activeTabId: string | null;
}

// Types
export type { ProjectData, PostData, MediaData, TaskProgress };

export interface ErrorDetails {
  message: string;
  title?: string;
  stack?: string;
}

// Re-export types from ConfirmDeleteModal for convenience
export type { DeleteReference, ConfirmDeleteDetails };

export type EditorMode = 'wysiwyg' | 'markdown' | 'preview';
export type GitDiffViewStyle = 'inline' | 'side-by-side';
export type PanelTab = 'tasks' | 'output' | 'post-links' | 'git-log';

export interface PanelOutputEntry {
  id: string;
  message: string;
  createdAt: string;
  kind: 'stdout' | 'result' | 'error';
}

export interface GitDiffPreferences {
  wordWrap: boolean;
  viewStyle: GitDiffViewStyle;
  hideUnchangedRegions: boolean;
}

// App State Store
interface AppState {
  // Projects
  projects: ProjectData[];
  activeProject: ProjectData | null;
  
  // Tabs
  tabs: Tab[];
  activeTabId: string | null;
  
  // UI State
  activeView: SidebarView;
  sidebarVisible: boolean;
  panelVisible: boolean;
  assistantSidebarVisible: boolean;
  panelActiveTab: PanelTab;
  panelOutputEntries: PanelOutputEntry[];
  selectedPostId: string | null;
  selectedMediaId: string | null;
  preferredEditorMode: EditorMode;
  picoTheme: import('../../main/shared/picoThemes').PicoThemeName | undefined;
  gitDiffPreferences: GitDiffPreferences;
  
  // Data
  posts: PostData[];
  media: MediaData[];
  tasks: TaskProgress[];
  
  // Pagination
  hasMorePosts: boolean;
  totalPosts: number;
  
  // Track which posts have unsaved changes (by post ID)
  dirtyPosts: Set<string>;
  
  // Error modal
  errorModal: ErrorDetails | null;

  // Confirm delete modal
  confirmDeleteModal: ConfirmDeleteDetails | null;
  
  // Loading states
  isLoading: boolean;
  error: string | null;

  // Chat token usage (keyed by conversationId, ephemeral - not persisted)
  chatTokenUsage: Record<string, {
    inputTokens: number;
    outputTokens: number;
    cacheReadTokens: number;
    cacheWriteTokens: number;
    totalTokens: number;
  }>;

  // Project Actions
  setProjects: (projects: ProjectData[]) => void;
  setActiveProject: (project: ProjectData | null) => void;
  addProject: (project: ProjectData) => void;
  updateProject: (id: string, project: Partial<ProjectData>) => void;
  removeProject: (id: string) => void;
  
  // Tab Actions
  openTab: (tab: { type: TabType; id: string; isTransient: boolean }) => void;
  openTabInBackground: (tab: { type: TabType; id: string; isTransient: boolean }) => void;
  closeTab: (id: string) => void;
  setActiveTab: (id: string) => void;
  pinTab: (id: string) => void;
  clearTabs: () => void;
  getTabState: () => TabState;
  restoreTabState: (state: TabState) => void;
  
  // Actions
  setActiveView: (view: SidebarView) => void;
  toggleSidebar: () => void;
  togglePanel: () => void;
  toggleAssistantSidebar: () => void;
  setPanelActiveTab: (tab: PanelTab) => void;
  appendPanelOutputEntry: (entry: PanelOutputEntry) => void;
  clearPanelOutputEntries: () => void;
  setSelectedPost: (id: string | null) => void;
  setSelectedMedia: (id: string | null) => void;
  setPreferredEditorMode: (mode: EditorMode) => void;
  setPicoTheme: (theme: import('../../main/shared/picoThemes').PicoThemeName | undefined) => void;
  setGitDiffPreferences: (preferences: GitDiffPreferences) => void;
  
  setPosts: (posts: PostData[], hasMore?: boolean, total?: number) => void;
  appendPosts: (posts: PostData[], hasMore: boolean) => void;
  addPost: (post: PostData) => void;
  updatePost: (id: string, post: Partial<PostData>) => void;
  removePost: (id: string) => void;
  
  // Dirty tracking
  markDirty: (id: string) => void;
  markClean: (id: string) => void;
  isDirty: (id: string) => boolean;
  
  // Error modal actions
  showErrorModal: (error: ErrorDetails) => void;
  hideErrorModal: () => void;

  // Confirm delete modal actions
  showConfirmDeleteModal: (details: ConfirmDeleteDetails) => void;
  hideConfirmDeleteModal: () => void;

  setMedia: (media: MediaData[]) => void;
  addMedia: (media: MediaData) => void;
  updateMedia: (id: string, media: Partial<MediaData>) => void;
  removeMedia: (id: string) => void;
  
  setTasks: (tasks: TaskProgress[]) => void;
  updateTask: (taskId: string, task: Partial<TaskProgress>) => void;
  
  // Loading Actions
  setLoading: (loading: boolean) => void;
  setError: (error: string | null) => void;

  // Chat token usage actions
  setChatTokenUsage: (conversationId: string, usage: {
    inputTokens: number;
    outputTokens: number;
    cacheReadTokens: number;
    cacheWriteTokens: number;
    totalTokens: number;
  }) => void;
  clearChatTokenUsage: (conversationId: string) => void;
}

export const useAppStore = create<AppState>()(
  persist(
    (set, get) => ({
      // Initial Project State
      projects: [],
      activeProject: null,
      
      // Initial Tabs State
      tabs: [],
      activeTabId: null,
      
      // Initial UI State
      activeView: 'posts',
      sidebarVisible: true,
      panelVisible: false,
      assistantSidebarVisible: false,
      panelActiveTab: 'tasks',
      panelOutputEntries: [],
      selectedPostId: null,
      selectedMediaId: null,
      preferredEditorMode: 'wysiwyg',
      picoTheme: undefined,
      gitDiffPreferences: {
        wordWrap: true,
        viewStyle: 'inline',
        hideUnchangedRegions: false,
      },
      
      // Initial Data
      posts: [],
      media: [],
      tasks: [],
      
      // Pagination
      hasMorePosts: false,
      totalPosts: 0,
      
      // Dirty posts tracking
      dirtyPosts: new Set<string>(),
      
      // Error modal
      errorModal: null,

      // Confirm delete modal
      confirmDeleteModal: null,
      
      // Initial Loading State
      isLoading: false,
      error: null,

      // Chat token usage (ephemeral, not persisted)
      chatTokenUsage: {},

      // Project Actions
      setProjects: (projects) => set({ projects }),
      setActiveProject: (activeProject) => set({ activeProject }),
      addProject: (project) => set((state) => ({ projects: [...state.projects, project] })),
      updateProject: (id, updatedProject) => set((state) => ({
        projects: state.projects.map((p) => (p.id === id ? { ...p, ...updatedProject } : p)),
      })),
      removeProject: (id) => set((state) => ({
        projects: state.projects.filter((p) => p.id !== id),
      })),
      
      // Tab Actions
      openTab: ({ type, id, isTransient }) => set((state) => {
        const existingTabIndex = state.tabs.findIndex((t) => t.id === id && t.type === type);
        
        if (existingTabIndex >= 0) {
          // Tab already exists - if trying to pin (isTransient=false), update it
          if (!isTransient) {
            const updatedTabs = [...state.tabs];
            updatedTabs[existingTabIndex] = { ...updatedTabs[existingTabIndex], isTransient: false };
            return { tabs: updatedTabs, activeTabId: id };
          }
          // Just switch to the existing tab
          return { activeTabId: id };
        }
        
        // If opening as transient, replace existing transient tab of the same type
        if (isTransient) {
          const transientIndex = state.tabs.findIndex((t) => t.isTransient && t.type === type);
          if (transientIndex >= 0) {
            const updatedTabs = [...state.tabs];
            updatedTabs[transientIndex] = { type, id, isTransient: true };
            return { tabs: updatedTabs, activeTabId: id };
          }
        }
        
        // Add new tab
        const newTab: Tab = { type, id, isTransient };
        return { tabs: [...state.tabs, newTab], activeTabId: id };
      }),

      openTabInBackground: ({ type, id, isTransient }) => set((state) => {
        const existingTabIndex = state.tabs.findIndex((t) => t.id === id && t.type === type);

        if (existingTabIndex >= 0) {
          if (!isTransient) {
            const updatedTabs = [...state.tabs];
            updatedTabs[existingTabIndex] = { ...updatedTabs[existingTabIndex], isTransient: false };
            return { tabs: updatedTabs };
          }
          return state;
        }

        const newTab: Tab = { type, id, isTransient };
        return { tabs: [...state.tabs, newTab] };
      }),

      closeTab: (id) => set((state) => {
        const tabIndex = state.tabs.findIndex((t) => t.id === id);
        if (tabIndex === -1) return state;
        
        const newTabs = state.tabs.filter((t) => t.id !== id);
        let newActiveTabId = state.activeTabId;
        
        // If closing the active tab, activate an adjacent tab
        if (state.activeTabId === id) {
          if (newTabs.length === 0) {
            newActiveTabId = null;
          } else if (tabIndex < newTabs.length) {
            // Activate the tab that moved into this position (next tab)
            newActiveTabId = newTabs[tabIndex].id;
          } else {
            // Activate the previous tab
            newActiveTabId = newTabs[newTabs.length - 1].id;
          }
        }
        
        return { tabs: newTabs, activeTabId: newActiveTabId };
      }),
      
      setActiveTab: (id) => set((state) => {
        // Only set if the tab exists
        const tabExists = state.tabs.some((t) => t.id === id);
        if (!tabExists) return state;
        return { activeTabId: id };
      }),
      
      pinTab: (id) => set((state) => ({
        tabs: state.tabs.map((t) => (t.id === id ? { ...t, isTransient: false } : t)),
      })),
      
      clearTabs: () => set({ tabs: [], activeTabId: null }),
      
      getTabState: () => {
        const state = get();
        return { tabs: state.tabs, activeTabId: state.activeTabId };
      },
      
      restoreTabState: (tabState) => set({ 
        tabs: tabState.tabs, 
        activeTabId: tabState.activeTabId 
      }),
      
      // UI Actions
      setActiveView: (view) => set({ activeView: view }),
      toggleSidebar: () => set((state) => ({ sidebarVisible: !state.sidebarVisible })),
      togglePanel: () => set((state) => ({ panelVisible: !state.panelVisible })),
      toggleAssistantSidebar: () => set((state) => ({ assistantSidebarVisible: !state.assistantSidebarVisible })),
      setPanelActiveTab: (panelActiveTab) => set({ panelActiveTab }),
      appendPanelOutputEntry: (entry) => set((state) => ({
        panelOutputEntries: [...state.panelOutputEntries, entry],
      })),
      clearPanelOutputEntries: () => set({ panelOutputEntries: [] }),
      setSelectedPost: (id) => set({ selectedPostId: id }),
      setSelectedMedia: (id) => set({ selectedMediaId: id }),
      setPreferredEditorMode: (mode) => set({ preferredEditorMode: mode }),
      setPicoTheme: (theme) => set({ picoTheme: theme }),
      setGitDiffPreferences: (preferences) => set({ gitDiffPreferences: preferences }),
      
      // Post Actions
      setPosts: (posts, hasMore = false, total = 0) => set({ posts, hasMorePosts: hasMore, totalPosts: total }),
      appendPosts: (newPosts, hasMore) => set((state) => {
        const existingIds = new Set(state.posts.map(p => p.id));
        const uniqueNewPosts = newPosts.filter(p => !existingIds.has(p.id));
        return {
          posts: [...state.posts, ...uniqueNewPosts],
          hasMorePosts: hasMore,
        };
      }),
      addPost: (post) => set((state) => {
        if (state.posts.some(p => p.id === post.id)) return state;
        return { posts: [post, ...state.posts], totalPosts: state.totalPosts + 1 };
      }),
      updatePost: (id, updatedPost) => set((state) => ({
        posts: state.posts.map((p) => (p.id === id ? { ...p, ...updatedPost } : p)),
      })),
      removePost: (id) => set((state) => {
        const newDirtyPosts = new Set(state.dirtyPosts);
        newDirtyPosts.delete(id);
        return {
          posts: state.posts.filter((p) => p.id !== id),
          dirtyPosts: newDirtyPosts,
          selectedPostId: state.selectedPostId === id ? null : state.selectedPostId,
        };
      }),
      
      // Dirty tracking
      markDirty: (id) => set((state) => {
        if (state.dirtyPosts.has(id)) return state;
        return { dirtyPosts: new Set([...state.dirtyPosts, id]) };
      }),
      
      markClean: (id) => set((state) => {
        const newDirtyPosts = new Set(state.dirtyPosts);
        newDirtyPosts.delete(id);
        return { dirtyPosts: newDirtyPosts };
      }),
      
      isDirty: (id) => get().dirtyPosts.has(id),
      
      // Error modal actions
      showErrorModal: (error) => set({ errorModal: error }),
      hideErrorModal: () => set({ errorModal: null }),

      // Confirm delete modal actions
      showConfirmDeleteModal: (details) => set({ confirmDeleteModal: details }),
      hideConfirmDeleteModal: () => set({ confirmDeleteModal: null }),

      // Media Actions
      setMedia: (media) => set({ media }),
      addMedia: (media) => set((state) => ({ media: [...state.media, media] })),
      updateMedia: (id, updatedMedia) => set((state) => ({
        media: state.media.map((m) => (m.id === id ? { ...m, ...updatedMedia } : m)),
      })),
      removeMedia: (id) => set((state) => ({
        media: state.media.filter((m) => m.id !== id),
        selectedMediaId: state.selectedMediaId === id ? null : state.selectedMediaId,
      })),
      
      // Task Actions
      setTasks: (tasks) => set({ tasks }),
      updateTask: (taskId, task) => set((state) => {
        const exists = state.tasks.some((t) => t.taskId === taskId);
        if (exists) {
          return { tasks: state.tasks.map((t) => (t.taskId === taskId ? { ...t, ...task } : t)) };
        }
        // Add new task if it doesn't exist yet
        return { tasks: [...state.tasks, { taskId, name: '', status: 'running', progress: 0, message: '', startTime: new Date().toISOString(), ...task } as TaskProgress] };
      }),
      
      // Loading Actions
      setLoading: (isLoading) => set({ isLoading }),
      setError: (error) => set({ error }),

      // Chat token usage actions
      setChatTokenUsage: (conversationId, usage) => set((state) => ({
        chatTokenUsage: { ...state.chatTokenUsage, [conversationId]: usage },
      })),
      clearChatTokenUsage: (conversationId) => set((state) => {
        const { [conversationId]: _, ...rest } = state.chatTokenUsage;
        return { chatTokenUsage: rest };
      }),
    }),
    {
      name: STORAGE_KEY,
      // Only persist UI state, not data (which is loaded from backend)
      partialize: (state) => ({
        activeView: state.activeView,
        sidebarVisible: state.sidebarVisible,
        panelVisible: state.panelVisible,
        panelActiveTab: state.panelActiveTab,
        selectedPostId: state.selectedPostId,
        selectedMediaId: state.selectedMediaId,
        preferredEditorMode: state.preferredEditorMode,
        picoTheme: state.picoTheme,
        gitDiffPreferences: state.gitDiffPreferences,
        // Tabs are persisted here for now (project-specific persistence handled separately)
        tabs: state.tabs,
        activeTabId: state.activeTabId,
        // Convert Set to array for storage
        dirtyPosts: [...state.dirtyPosts],
      }),
      // Merge function to restore Set from array
      merge: (persisted, current) => {
        const persistedState = persisted as Partial<AppState> & { dirtyPosts?: string[]; tabs?: Tab[] };
        return {
          ...current,
          ...persistedState,
          tabs: persistedState.tabs || [],
          activeTabId: persistedState.activeTabId || null,
          panelActiveTab: persistedState.panelActiveTab || current.panelActiveTab,
          dirtyPosts: new Set(persistedState.dirtyPosts || []),
          picoTheme: persistedState.picoTheme || current.picoTheme,
          gitDiffPreferences: persistedState.gitDiffPreferences || current.gitDiffPreferences,
        };
      },
    }
  )
);
