"use client";

import React, { ReactNode, useCallback, useEffect, useState } from "react";
import { del, get, post } from "../../lib/api";

export interface Settings {
  [key: string]: any;
}

export interface Dataset {
  [path: string]: any;
}

export interface DatasetsConfig {
  [datasetName: string]: Dataset;
}

export interface QueueConfig {
  maxConcurrent?: number;
  maxRetries?: number;
  [key: string]: any;
}

export interface WatcherConfig {
  enabled?: boolean;
  [key: string]: any;
}

export interface AppContextType {
  // Data
  settings: Settings | null;
  datasetsConfig: DatasetsConfig | null;
  queueConfig: QueueConfig | null;
  watcherConfig: WatcherConfig | null;
  datasets: string[] | null;

  // Loading states
  isLoading: boolean;
  isInitialized: boolean;

  // Errors
  error: Error | null;

  // Mutation functions
  updateSetting: (key: string, value: any) => Promise<void>;
  deleteSetting: (key: string) => Promise<void>;
  updateDatasets: (datasets: DatasetsConfig) => Promise<void>;
  updateQueueConfig: (config: QueueConfig) => Promise<void>;
  updateWatcherConfig: (config: WatcherConfig) => Promise<void>;

  // Refresh functions
  refreshSettings: () => Promise<void>;
  refreshDatasets: () => Promise<void>;
  refreshAll: () => Promise<void>;
}

const AppContext = React.createContext<AppContextType | undefined>(undefined);

export function AppProvider({ children }: { children: ReactNode }) {
  const [settings, setSettings] = useState<Settings | null>(null);
  const [datasetsConfig, setDatasetsConfig] = useState<DatasetsConfig | null>(
    null
  );
  const [queueConfig, setQueueConfig] = useState<QueueConfig | null>(null);
  const [watcherConfig, setWatcherConfig] = useState<WatcherConfig | null>(
    null
  );
  const [datasets, setDatasets] = useState<string[] | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isInitialized, setIsInitialized] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  // Load all initial data
  const initializeData = useCallback(async () => {
    try {
      setIsLoading(true);
      setError(null);

      // Load settings
      const settingsData = await get("/config/settings");
      setSettings(settingsData || {});

      // Extract specific configs from settings
      if (settingsData) {
        const queue = settingsData.queue || {};
        const watcher = settingsData.watcher || {};
        const datasetsData = settingsData.datasets || {};

        setQueueConfig(queue);
        setWatcherConfig(watcher);
        setDatasetsConfig(datasetsData);
      }

      // Load datasets list
      const datasetsList = await get("/files/all-datasets");
      setDatasets(datasetsList || []);

      setIsInitialized(true);
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      console.error("Failed to initialize app context:", error);
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Initial load
  useEffect(() => {
    initializeData();
  }, [initializeData]);

  const refreshSettings = useCallback(async () => {
    try {
      const settingsData = await get("/config/settings");
      setSettings(settingsData || {});
      if (settingsData) {
        setQueueConfig(settingsData.queue || {});
        setWatcherConfig(settingsData.watcher || {});
        setDatasetsConfig(settingsData.datasets || {});
      }
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      throw error;
    }
  }, []);

  const refreshDatasets = useCallback(async () => {
    try {
      const datasetsList = await get("/files/all-datasets");
      setDatasets(datasetsList || []);
    } catch (err) {
      const error = err instanceof Error ? err : new Error(String(err));
      setError(error);
      throw error;
    }
  }, []);

  // Listen for WebSocket events
  useEffect(() => {
    const handleSettingsUpdate = () => {
      refreshSettings();
    };

    const handleTaskUpdate = () => {
      // Refetch datasets in case new ones were created
      refreshDatasets();
    };

    const handleFileUpdate = () => {
      // Refetch datasets in case new ones were created
      refreshDatasets();
    };

    window.addEventListener(
      "settingsUpdate",
      handleSettingsUpdate as EventListener
    );
    window.addEventListener("taskUpdate", handleTaskUpdate as EventListener);
    window.addEventListener("fileUpdate", handleFileUpdate as EventListener);

    return () => {
      window.removeEventListener(
        "settingsUpdate",
        handleSettingsUpdate as EventListener
      );
      window.removeEventListener(
        "taskUpdate",
        handleTaskUpdate as EventListener
      );
      window.removeEventListener(
        "fileUpdate",
        handleFileUpdate as EventListener
      );
    };
  }, [refreshSettings, refreshDatasets]);

  // Mutation functions
  const updateSetting = useCallback(
    async (key: string, value: any) => {
      try {
        await post("/config/settings", { [key]: value });
        setSettings((prev) =>
          prev ? { ...prev, [key]: value } : { [key]: value }
        );
        await initializeData();
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [initializeData]
  );

  const deleteSetting = useCallback(
    async (key: string) => {
      try {
        await del(`/config/settings/${key}`);
        setSettings((prev) => {
          if (!prev) return null;
          const updated = { ...prev };
          delete updated[key];
          return updated;
        });
        await initializeData();
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [initializeData]
  );

  const updateDatasets = useCallback(
    async (datasetsData: DatasetsConfig) => {
      try {
        setDatasetsConfig(datasetsData);
        await updateSetting("datasets", datasetsData);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [updateSetting]
  );

  const updateQueueConfig = useCallback(
    async (config: QueueConfig) => {
      try {
        setQueueConfig(config);
        await updateSetting("queue", config);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [updateSetting]
  );

  const updateWatcherConfig = useCallback(
    async (config: WatcherConfig) => {
      try {
        setWatcherConfig(config);
        await updateSetting("watcher", config);
      } catch (err) {
        const error = err instanceof Error ? err : new Error(String(err));
        setError(error);
        throw error;
      }
    },
    [updateSetting]
  );

  const refreshAll = useCallback(async () => {
    await initializeData();
  }, [initializeData]);

  const value: AppContextType = {
    settings,
    datasetsConfig,
    queueConfig,
    watcherConfig,
    datasets,
    isLoading,
    isInitialized,
    error,
    updateSetting,
    deleteSetting,
    updateDatasets,
    updateQueueConfig,
    updateWatcherConfig,
    refreshSettings,
    refreshDatasets,
    refreshAll
  };

  return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
}

export function useAppContext() {
  const context = React.useContext(AppContext);
  if (context === undefined) {
    throw new Error("useAppContext must be used within an AppProvider");
  }
  return context;
}
