import React, { useEffect, useState } from 'react';
import { Add, ArrowDropDown, Delete, Settings } from '@mui/icons-material';
import { DatabaseInfo, useAppDispatch, useDatabaseAPI, useSchemaGraph, useSessionCache } from '@graphpolaris/shared/lib/data-access';
import { updateCurrentDatabase } from '@graphpolaris/shared/lib/data-access/store/sessionSlice';
import { SettingsForm } from './forms/settings';
import { NewDatabaseForm } from './forms/AddDatabase/newdatabase';
import { LoadingSpinner } from '@graphpolaris/shared/lib/components/LoadingSpinner';
import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice';
import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
import { clearSchema } from '@graphpolaris/shared/lib/data-access/store/schemaSlice';

export default function DatabaseSelector({}) {
  const dispatch = useAppDispatch();
  const api = useDatabaseAPI();
  const session = useSessionCache();
  const schemaGraph = useSchemaGraph();
  const dbSelectionMenuRef = React.useRef<HTMLDivElement>(null);
  const [hovered, setHovered] = useState<string | null>(null);
  const [connecting, setConnecting] = useState<boolean>(false);
  const [dbSelectionMenuOpen, setDbSelectionMenuOpen] = useState<boolean>(false);
  const [settingsMenuOpen, setSettingsMenuOpen] = useState<boolean>(false);
  const [selectedDatabase, setSelectedDatabase] = useState<DatabaseInfo | null>(null);
  const [addDatabaseFormOpen, setAddDatabaseFormOpen] = useState<boolean>(false);

  useEffect(() => {
    const handleClickOutside = ({ target }: MouseEvent) => {
      if (dbSelectionMenuRef.current && !dbSelectionMenuRef.current.contains(target as Node)) {
        setDbSelectionMenuOpen(false);
      }
    };
    document.addEventListener('click', handleClickOutside);
    return () => {
      document.removeEventListener('click', handleClickOutside);
    };
  }, []);

  useEffect(() => {
    setConnecting(false);
  }, [schemaGraph]);

  useEffect(() => {
    let timeoutId: ReturnType<typeof setTimeout>;
    if (connecting) {
      timeoutId = setTimeout(() => {
        dispatch(addError("Couldn't establish connection"));
        setConnecting(false);
        dispatch(updateCurrentDatabase(undefined));
        dispatch(clearQB());
        dispatch(clearSchema());
      }, 10000);
    }

    return () => {
      if (timeoutId) {
        clearTimeout(timeoutId);
      }
    };
  }, [connecting]);

  return (
    <>
      <SettingsForm
        open={settingsMenuOpen}
        database={selectedDatabase}
        onClose={() => {
          setSettingsMenuOpen(false);
        }}
      />
      <NewDatabaseForm
        open={addDatabaseFormOpen}
        onClose={() => {
          setAddDatabaseFormOpen(false);
        }}
      />
      <div
        className="relative flex-shrink max-md:flex-grow border w-full xl:w-[30rem] min-w-0 max-h-full ml-auto mr-auto cursor-pointer"
        ref={dbSelectionMenuRef}
      >
        <div
          className="flex w-full px-4 py-2 hover:bg-slate-200 transition-colors duration-300"
          onClick={() => {
            if (session.databases?.length === 0) setAddDatabaseFormOpen(true);
            else setDbSelectionMenuOpen(!dbSelectionMenuOpen);
          }}
        >
          <div className="flex items-center w-full shrink-0">
            {connecting ? (
              <>
                <LoadingSpinner />
                <p className="ml-2 truncate">
                  <span className="max-md:hidden">Connecting to </span>
                  {session.currentDatabase}
                </p>
              </>
            ) : session.currentDatabase ? (
              <>
                <div className="h-[8px] w-[8px] shrink-0 rounded-full bg-green-500" />
                <p className="ml-2 truncate">
                  <span className="max-md:hidden">Connected DB: </span>
                  {session.currentDatabase}
                </p>
              </>
            ) : session.databases === undefined ? (
              <>
                <LoadingSpinner />
                <p className="ml-2">Retrieving databases</p>
              </>
            ) : session.databases?.length === 0 ? (
              <>
                <p className="ml-2">Add your first Database</p>
              </>
            ) : (
              <>
                <div className="h-2 w-2 rounded-full bg-slate-500" />
                <p className="ml-2">Select a database</p>
              </>
            )}
          </div>
          <ArrowDropDown />
        </div>
        {dbSelectionMenuOpen && session.databases && (
          <div className="absolute w-full top-11 z-50 bg-slate-100 border">
            <div
              className="flex items-center p-2 hover:bg-slate-200"
              onClick={(e) => {
                e.preventDefault();
                setDbSelectionMenuOpen(false);
                setConnecting(false);
                setAddDatabaseFormOpen(true);
              }}
              title="Add new database"
            >
              {session.databases.length === 0 ? (
                <>
                  <Add />
                  <p className="ml-2">Add your first database</p>
                </>
              ) : (
                <>
                  <Add />
                  <p className="ml-2">Add database</p>
                </>
              )}
            </div>
            {session.databases.map((db) => (
              <div
                key={db.Name}
                className="flex justify-between items-center px-4 py-2 hover:bg-slate-200 gap-2"
                onClick={(e) => {
                  if (db.Name !== session.currentDatabase) {
                    e.preventDefault();
                    setDbSelectionMenuOpen(false);
                    setConnecting(true);
                    dispatch(updateCurrentDatabase(db.Name));
                    dispatch(clearQB());
                    dispatch(clearSchema());
                  } else {
                    setDbSelectionMenuOpen(false);
                  }
                }}
                onMouseEnter={() => setHovered(db.Name)}
                onMouseLeave={() => setHovered(null)}
                title={`Connect to ${db.Name}`}
              >
                <div className={`h-[8px] w-[8px] rounded-full shrink-0 ${db.status ? 'bg-green-500' : 'bg-red-500'}`} />
                <div className="w-full shrink min-w-0 flex flex-col">
                  <p className="truncate w-full shrink-0 min-w-0">{db.Name}</p>
                  <p className="text-xs text-slate-400 truncate w-fit shrink-0 min-w-0 max-w-full h-full border border-slate-300 rounded-sm p-0.5">
                    {db.Protocol}
                    {db.URL}
                  </p>
                </div>
                {hovered === db.Name && (
                  <div className="flex items-center ml-2">
                    <div
                      className="text-slate-700 hover:text-slate-400 transition-colors duration-300"
                      onClick={(e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        setSettingsMenuOpen(true);
                        setSelectedDatabase(db);
                      }}
                    >
                      <Settings />
                    </div>
                    <div
                      className="text-slate-700 hover:text-slate-400 transition-colors duration-300"
                      onClick={(e) => {
                        e.preventDefault();
                        dispatch(updateCurrentDatabase(undefined));
                        dispatch(clearQB());
                        dispatch(clearSchema());
                        api.DeleteDatabase(db.Name);
                      }}
                      title="Delete database"
                    >
                      <Delete />
                    </div>
                  </div>
                )}
              </div>
            ))}
          </div>
        )}
      </div>
    </>
  );
}