import React, {createContext, useState, useContext, useCallback, useEffect} from 'react';
import {collectionService} from '@/services/collectionService';
import {apiRequestService} from '@/services/apiRequestService';
import {serverService} from '@/services/serverService';
import {authService} from '@/services/authService';
import APIClient from '@/services/APIClient.js';

const APIContext = createContext(null);

export const useAPI = () => {
  const context = useContext(APIContext);
  if (!context) {
    throw new Error('useAPI must be used within an APIProvider');
  }
  return context;
};

export const APIProvider = ({
  children,
  contextPath = '/'
}) => {
  const [apiClient] = useState(() => new APIClient());
  const [collections, setCollections] = useState([]);
  const [apiRequests, setApiRequests] = useState([]);
  const [servers, setServers] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  // Initialize services
  const collections$ = collectionService(contextPath);
  const apiRequests$ = apiRequestService(contextPath);
  const servers$ = serverService();
  const auth$ = authService();

  const handleLogout = useCallback(async () => {
    try {
      setIsAuthenticated(false);
      setCollections([]);
      setApiRequests([]);
      setServers([]);
      return true;
    } catch (err) {
      console.error('Logout failed:', err);
      return false;
    }
  }, []);

  const loadServers = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const validatedServers = await servers$.loadServers();
      setServers(validatedServers);
      console.log({validatedServers});
      return validatedServers;
    } catch (err) {
      setError(err.message);
      console.log({err});
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  const getServer = useCallback((serverId) => {
    const server = servers.find(server => server.id === serverId);
    console.log(server);
    return server;
  }, [servers]);

  const loadCollections = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const processedCollections = await collections$.loadCollections();
      setCollections(processedCollections);
      return processedCollections;
    } catch (err) {
      setError(err.message);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  const createCollection = useCallback(async (name) => {
    setLoading(true);
    setError(null);
    try {
      await collections$.createCollection(name);
      const updatedCollections = await collections$.loadCollections();
      setCollections(updatedCollections);
    } catch (err) {
      setError(err.message);
      return null;
    } finally {
      setLoading(false);
    }
  }, []);

  const updateCollection = useCallback(async (id, name) => {
    setLoading(true);
    setError(null);
    try {
      await collections$.updateCollection(id, name);
      setCollections(prev =>
          prev.map(collection =>
              collection.id === id ? {...collection, name} : collection
          )
      );
      return true;
    } catch (err) {
      setError(err.message);
      return false;
    } finally {
      setLoading(false);
    }
  }, []);

  const deleteCollection = useCallback(async (id) => {
    setLoading(true);
    setError(null);
    try {
      await collections$.deleteCollection(id);
      setCollections(prev => prev.filter(collection => collection.id !== id));
      return true;
    } catch (err) {
      setError(err.message);
      return false;
    } finally {
      setLoading(false);
    }
  }, []);

  const createAPIRequest = useCallback(async (collectionId, apiData) => {
    setLoading(true);
    setError(null);
    try {
      const newApiRequest = await apiRequests$.createAPIRequest(collectionId, apiData);

      setCollections(prev =>
          prev.map(collection =>
              collection.id === collectionId
                  ? {...collection, apis: [...(collection.apis || []), newApiRequest]}
                  : collection
          )
      );

      setApiRequests(prev => [...prev, newApiRequest]);
      return newApiRequest;
    } catch (err) {
      setError(err.message);
      return null;
    } finally {
      setLoading(false);
    }
  }, []);

  const updateAPIRequest = useCallback(async (apiRequest) => {
    setLoading(true);
    setError(null);
    try {
      await apiRequests$.updateAPIRequest(apiRequest);

      setCollections(prev =>
          prev.map(collection => {
            if (collection.id === apiRequest.collectionId) {
              return {
                ...collection,
                apis: collection.apis.map(api =>
                    api.id === apiRequest.id ? apiRequest : api
                )
              };
            }
            return collection;
          })
      );

      setApiRequests(prev =>
          prev.map(req => req.id === apiRequest.id ? apiRequest : req)
      );

      return apiRequest;
    } catch (err) {
      setError(err.message);
      return null;
    } finally {
      setLoading(false);
    }
  }, []);

  const deleteAPIRequest = useCallback(async (collectionId, apiId) => {
    setLoading(true);
    setError(null);
    try {
      await apiRequests$.deleteAPIRequest(collectionId, apiId);

      setCollections(prev =>
          prev.map(collection => {
            if (collection.id === collectionId) {
              return {
                ...collection,
                apis: collection.apis.filter(api => api.id !== apiId)
              };
            }
            return collection;
          })
      );

      setApiRequests(prev => prev.filter(req => req.id !== apiId));
      return true;
    } catch (err) {
      setError(err.message);
      return false;
    } finally {
      setLoading(false);
    }
  }, []);

  const sendAPIRequest = useCallback(async (apiRequest, preProcessCallback, consoleOutput) => {
    try {
      return await apiClient.sendAPIRequest(apiRequest, preProcessCallback, consoleOutput);
    } catch (err) {
      setError(err.message);
      return null;
    }
  }, [apiClient]);

  const contextValue = {
    apiClient,
    collections,
    apiRequests,
    servers,
    loadServers,
    getServer,
    loading,
    error,
    loadCollections,
    createCollection,
    updateCollection,
    deleteCollection,
    createAPIRequest,
    updateAPIRequest,
    deleteAPIRequest,
    sendAPIRequest,
    isAuthenticated,
    setIsAuthenticated,
    handleLogout
  };

  return (
      <APIContext.Provider value={contextValue}>
        {children}
      </APIContext.Provider>
  );
};

export default APIProvider;
