import React, { useEffect, useState, useCallback } from 'react';
import {
  useAppDispatch,
  useSchemaGraph,
  useSessionCache,
  useAuthorizationCache,
  useCheckPermissionPolicy,
} from '@graphpolaris/shared/lib/data-access';
import { deleteSaveState, selectSaveState } from '@graphpolaris/shared/lib/data-access/store/sessionSlice';
import { SettingsForm } from './forms/settings';
import { LoadingSpinner } from '@graphpolaris/shared/lib/components/LoadingSpinner';
import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice';
import { DropdownTrigger, DropdownContainer, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns';
import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
import { clearSchema } from '@graphpolaris/shared/lib/data-access/store/schemaSlice';
import { DatabaseStatus, SaveStateI, nilUUID, wsDeleteState } from '@graphpolaris/shared/lib/data-access/broker';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
import { Icon } from '@graphpolaris/shared';

export default function DatabaseSelector({}) {
  const dispatch = useAppDispatch();
  const session = useSessionCache();
  const schemaGraph = useSchemaGraph();
  const authCache = useAuthorizationCache();
  const [hovered, setHovered] = useState<string | null>(null);
  const [connecting, setConnecting] = useState<boolean>(false);
  const [dbSelectionMenuOpen, setDbSelectionMenuOpen] = useState<boolean>(false);
  const [settingsMenuOpen, setSettingsMenuOpen] = useState<'add' | 'update' | undefined>(undefined);
  const [selectedSaveState, setSelectedSaveState] = useState<SaveStateI | null>(null);
  // const [addDbConnectionFormOpen, setAddDbConnectionFormOpen] = useState<boolean>(false);

  useEffect(() => {
    if (
      (!session.fetchingSaveStates &&
        session.saveStates &&
        Object.keys(session.saveStates).length === 0 &&
        settingsMenuOpen === undefined) ||
      session.currentSaveState === nilUUID
    ) {
      setSettingsMenuOpen('add');
    }
  }, [session, settingsMenuOpen]);

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

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

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

  const { canRead, canWrite } = useCheckPermissionPolicy();
  const [readAllowed, setReadAllowed] = useState(false);
  const [writeAllowed, setWriteAllowed] = useState(false);
  const resource = 'database';

  const checkReadPermission = useCallback(async () => {
    const result = await canRead(resource);
    setReadAllowed(result);
  }, [canRead]);

  const checkWritePermission = useCallback(async () => {
    const result = await canWrite(resource);
    setWriteAllowed(result);
  }, [canWrite]);

  useEffect(() => {
    checkReadPermission();
  }, [checkReadPermission]);

  useEffect(() => {
    checkWritePermission();
  }, [checkWritePermission]);

  return (
    <div className="menu-walkthrough">
      <TooltipProvider delayDuration={1000}>
        {settingsMenuOpen !== undefined && (
          <SettingsForm
            open={settingsMenuOpen}
            saveState={settingsMenuOpen === 'update' ? selectedSaveState : null}
            disableCancel={
              (session.saveStates && Object.keys(session.saveStates).length === 0) ||
              session.currentSaveState === '00000000-0000-0000-0000-000000000000'
            }
            onClose={() => {
              setSettingsMenuOpen(undefined);
            }}
          />
        )}
        <DropdownContainer
          open={dbSelectionMenuOpen}
          onOpenChange={(ret) => {
            if (!ret) {
              if (session.saveStates && Object.keys(session.saveStates).length === 0) setSettingsMenuOpen('add');
              else setDbSelectionMenuOpen(!dbSelectionMenuOpen);
            } else {
              setDbSelectionMenuOpen(true);
            }
          }}
        >
          <DropdownTrigger
            onClick={() => {
              if (connecting || authCache.authorized === false || !!authCache.roomID || writeAllowed) {
                console.debug('User blocked from editing query due to being a viewer');
                setDbSelectionMenuOpen(!dbSelectionMenuOpen);
              }
            }}
            className="w-[18rem]"
            size="md"
            disabled={connecting || authCache.authorized === false || !!authCache.roomID || !writeAllowed}
            title={
              <div className="flex items-center">
                {connecting && session.currentSaveState && session.currentSaveState in session.saveStates ? (
                  <>
                    <LoadingSpinner />
                    <p className="ml-2 truncate">Connecting to {session.saveStates[session.currentSaveState].name}</p>
                  </>
                ) : session.currentSaveState && session.currentSaveState in session.saveStates && session.currentSaveState !== nilUUID ? (
                  <div className="flex">
                    <Icon component="icon-[ic--outline-storage]" size={20} className=" self-center" />
                    <span className="relative">
                      <span
                        className={`absolute bottom-0.5 right-3 h-2 w-2 border border-light  rounded-full ${session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'}`}
                      />
                    </span>
                    <p className="ml-2 truncate">{session.saveStates[session.currentSaveState].name}</p>
                  </div>
                ) : session.saveStates === undefined ? (
                  <>
                    <LoadingSpinner />
                    <p className="ml-2">Retrieving databases</p>
                  </>
                ) : Object.keys(session.saveStates).length === 0 || session.currentSaveState === nilUUID ? (
                  <>
                    <p className="ml-2">Add your first Database</p>
                  </>
                ) : (
                  <>
                    <div className="h-2 w-2 rounded-full bg-secondary-500" />
                    <p className="ml-2">Select a database</p>
                  </>
                )}
              </div>
            }
          />

          {session.saveStates !== undefined && (
            <DropdownItemContainer>
              <li
                className="flex items-center p-2 hover:bg-secondary-50 cursor-pointer"
                onClick={(e) => {
                  e.preventDefault();
                  setDbSelectionMenuOpen(false);
                  setConnecting(false);
                  setSettingsMenuOpen('add');
                }}
              >
                {session.saveStates && Object.keys(session.saveStates).length === 0 ? (
                  <>
                    <Icon component="icon-[ic--baseline-add]" size={24} />
                    <p className="ml-2">Add your first database</p>
                  </>
                ) : (
                  <>
                    <Icon component="icon-[ic--baseline-add]" size={24} />
                    <p className="ml-2">Add database</p>
                  </>
                )}
              </li>
              {Object.values(session.saveStates)
                .filter((save) => save.id !== nilUUID)
                .map((save) => (
                  <li
                    key={save.id}
                    className="flex justify-between items-center px-4 py-2 hover:bg-primary-100 gap-2 cursor-pointer"
                    onClick={(e) => {
                      if (save.id !== session.currentSaveState) {
                        e.preventDefault();
                        setDbSelectionMenuOpen(false);
                        setConnecting(true);
                        dispatch(selectSaveState(save.id));
                        dispatch(clearQB());
                        dispatch(clearSchema());
                      } else {
                        setDbSelectionMenuOpen(false);
                      }
                    }}
                    onMouseEnter={() => setHovered(save.id)}
                    onMouseLeave={() => setHovered(null)}
                  >
                    <Tooltip placement={'left'}>
                      <TooltipTrigger>
                        <div
                          className={`h-[8px] w-[8px] rounded-full shrink-0 ${
                            session.testedSaveState[save.id] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'
                          }`}
                        />
                      </TooltipTrigger>
                      <TooltipContent>
                        <p>
                          {session.testedSaveState[save.id] === DatabaseStatus.tested
                            ? 'Database connection tested'
                            : 'Something went wrong when trying to connect'}
                        </p>
                      </TooltipContent>
                    </Tooltip>
                    <div className="w-full shrink min-w-0 flex flex-col">
                      <p className="truncate w-full shrink-0 min-w-0">{save.name}</p>
                      <p className="bg-light text-2xs text-secondary-500 truncate w-fit shrink-0 min-w-0 max-w-full h-full border border-secondary-200 rounded-sm p-0.5">
                        {save.db.protocol}
                        {save.db.url}
                      </p>
                    </div>
                    <div className={`flex items-center ml-2 ${hovered === save.id ? 'display' : 'invisible'}`}>
                      <div
                        className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300"
                        onClick={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                          setSettingsMenuOpen('update');
                          setSelectedSaveState(save);
                        }}
                      >
                        <Tooltip>
                          <TooltipTrigger>
                            <Icon component="icon-[ic--baseline-settings]" size={24} />
                          </TooltipTrigger>
                          <TooltipContent>
                            <p>Change the connection details</p>
                          </TooltipContent>
                        </Tooltip>
                      </div>
                      <div
                        className="text-secondary-700 hover:text-secondary-400 transition-colors duration-300"
                        onClick={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                          setDbSelectionMenuOpen(false);
                          if (session.currentSaveState === save.id) {
                            dispatch(clearQB());
                            dispatch(clearSchema());
                          }
                          wsDeleteState(save.id);
                          dispatch(deleteSaveState(save.id));
                        }}
                      >
                        <Tooltip>
                          <TooltipTrigger>
                            <Icon component="icon-[ic--baseline-delete]" size={24} />
                          </TooltipTrigger>
                          <TooltipContent>
                            <p>Delete the database</p>
                          </TooltipContent>
                        </Tooltip>
                      </div>
                    </div>
                  </li>
                ))}
            </DropdownItemContainer>
          )}
        </DropdownContainer>
      </TooltipProvider>
    </div>
  );
}