import { type } from '@tauri-apps/plugin-os';
import { settingsAtom, workspacesAtom } from '@yaakapp-internal/models';
import classNames from 'classnames';
import { useAtomValue } from 'jotai';
import * as m from 'motion/react-m';
import { useMemo } from 'react';
import {
  useEnsureActiveCookieJar,
  useSubscribeActiveCookieJarId,
} from '../hooks/useActiveCookieJar';
import {
  activeEnvironmentAtom,
  useSubscribeActiveEnvironmentId,
} from '../hooks/useActiveEnvironment';
import { activeFolderAtom } from '../hooks/useActiveFolder';
import { useSubscribeActiveFolderId } from '../hooks/useActiveFolderId';
import { activeRequestAtom } from '../hooks/useActiveRequest';
import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId';
import { activeWorkspaceAtom } from '../hooks/useActiveWorkspace';
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
import { useHotKey } from '../hooks/useHotKey';
import { useSubscribeRecentCookieJars } from '../hooks/useRecentCookieJars';
import { useSubscribeRecentEnvironments } from '../hooks/useRecentEnvironments';
import { useSubscribeRecentRequests } from '../hooks/useRecentRequests';
import { useSubscribeRecentWorkspaces } from '../hooks/useRecentWorkspaces';
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
import { useSidebarHidden } from '../hooks/useSidebarHidden';
import { useSidebarWidth } from '../hooks/useSidebarWidth';
import { useSyncWorkspaceRequestTitle } from '../hooks/useSyncWorkspaceRequestTitle';
import { duplicateRequestOrFolderAndNavigate } from '../lib/duplicateRequestOrFolderAndNavigate';
import { importData } from '../lib/importData';
import { jotaiStore } from '../lib/jotai';
import { CreateDropdown } from './CreateDropdown';
import { Banner } from './core/Banner';
import { Button } from './core/Button';
import { HotkeyList } from './core/HotkeyList';
import { FeedbackLink } from './core/Link';
import { HStack } from './core/Stacks';
import { ErrorBoundary } from './ErrorBoundary';
import { FolderLayout } from './FolderLayout';
import { GrpcConnectionLayout } from './GrpcConnectionLayout';
import { HeaderSize, SidebarLayout } from '@yaakapp-internal/ui';
import { HttpRequestLayout } from './HttpRequestLayout';
import { Overlay } from './Overlay';
import Sidebar from './Sidebar';
import { SidebarActions } from './SidebarActions';
import { WebsocketRequestLayout } from './WebsocketRequestLayout';
import { WorkspaceHeader } from './WorkspaceHeader';

const head = { gridArea: 'head' };
const body = { gridArea: 'body' };

export function Workspace() {
  // First, subscribe to some things applicable to workspaces
  useGlobalWorkspaceHooks();

  const workspaces = useAtomValue(workspacesAtom);
  const settings = useAtomValue(settingsAtom);
  const osType = type();
  const [width, setWidth, resetWidth] = useSidebarWidth();
  const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
  const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
  const activeEnvironment = useAtomValue(activeEnvironmentAtom);
  const floating = useShouldFloatSidebar();

  const environmentBgStyle = useMemo(() => {
    if (activeEnvironment?.color == null) return undefined;
    const background = `linear-gradient(to right, ${activeEnvironment.color} 15%, transparent 40%)`;
    return { background };
  }, [activeEnvironment?.color]);

  // We're loading still
  if (workspaces.length === 0) {
    return null;
  }

  const header = (
    <HeaderSize
      data-tauri-drag-region
      size="lg"
      className="relative x-theme-appHeader bg-surface"
      osType={osType}
      hideWindowControls={settings.hideWindowControls}
      useNativeTitlebar={settings.useNativeTitlebar}
      interfaceScale={settings.interfaceScale}
    >
      <div className="absolute inset-0 pointer-events-none">
        <div
          style={environmentBgStyle}
          className="absolute inset-0 opacity-[0.07]"
        />
        <div
          style={environmentBgStyle}
          className="absolute left-0 right-0 -bottom-[1px] h-[1px] opacity-20"
        />
      </div>
      <WorkspaceHeader className="pointer-events-none" />
    </HeaderSize>
  );

  const workspaceBody = (
    <ErrorBoundary name="Workspace Body">
      <WorkspaceBody />
    </ErrorBoundary>
  );

  const sidebarContent = (
    <div className="x-theme-sidebar overflow-hidden bg-surface h-full">
      <ErrorBoundary name="Sidebar">
        <Sidebar className="border-r border-border-subtle" />
      </ErrorBoundary>
    </div>
  );

  return (
    <div className="grid w-full h-full grid-rows-[auto_1fr]">
      {header}
      {floating ? (
        <>
          <Overlay
            open={!floatingSidebarHidden}
            portalName="sidebar"
            onClose={() => setFloatingSidebarHidden(true)}
            zIndex={20}
          >
            <m.div
              initial={{ opacity: 0, x: -20 }}
              animate={{ opacity: 1, x: 0 }}
              className={classNames(
                'x-theme-sidebar',
                'absolute top-0 left-0 bottom-0 bg-surface border-r border-border-subtle w-[20rem]',
                'grid grid-rows-[auto_1fr]',
              )}
            >
              <HeaderSize hideControls size="lg" className="border-transparent flex items-center" osType={osType} hideWindowControls={settings.hideWindowControls} useNativeTitlebar={settings.useNativeTitlebar} interfaceScale={settings.interfaceScale}>
                <SidebarActions />
              </HeaderSize>
              <ErrorBoundary name="Sidebar (Floating)">
                <Sidebar />
              </ErrorBoundary>
            </m.div>
          </Overlay>
          {workspaceBody}
        </>
      ) : (
        <SidebarLayout
          width={width ?? 250}
          onWidthChange={setWidth}
          hidden={sidebarHidden ?? false}
          onHiddenChange={(hidden) => setSidebarHidden(hidden)}
          sidebar={sidebarContent}
        >
          {workspaceBody}
        </SidebarLayout>
      )}
    </div>
  );
}

function WorkspaceBody() {
  const activeRequest = useAtomValue(activeRequestAtom);
  const activeFolder = useAtomValue(activeFolderAtom);
  const activeWorkspace = useAtomValue(activeWorkspaceAtom);

  if (activeWorkspace == null) {
    return (
      <m.div
        className="m-auto"
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        // Delay the entering because the workspaces might load after a slight delay
        transition={{ delay: 0.5 }}
      >
        <Banner color="warning" className="max-w-[30rem]">
          The active workspace was not found. Select a workspace from the header menu or report this
          bug to <FeedbackLink />
        </Banner>
      </m.div>
    );
  }

  if (activeRequest?.model === 'grpc_request') {
    return <GrpcConnectionLayout style={body} />;
  }
  if (activeRequest?.model === 'websocket_request') {
    return <WebsocketRequestLayout style={body} activeRequest={activeRequest} />;
  }
  if (activeRequest?.model === 'http_request') {
    return <HttpRequestLayout activeRequest={activeRequest} style={body} />;
  }
  if (activeFolder != null) {
    return <FolderLayout folder={activeFolder} style={body} />;
  }

  return (
    <HotkeyList
      hotkeys={['model.create', 'sidebar.focus', 'settings.show']}
      bottomSlot={
        <HStack space={1} justifyContent="center" className="mt-3">
          <Button variant="border" size="sm" onClick={() => importData.mutate()}>
            Import
          </Button>
          <CreateDropdown hideFolder>
            <Button variant="border" forDropdown size="sm">
              New Request
            </Button>
          </CreateDropdown>
        </HStack>
      }
    />
  );
}

function useGlobalWorkspaceHooks() {
  useEnsureActiveCookieJar();

  useSubscribeActiveRequestId();
  useSubscribeActiveFolderId();
  useSubscribeActiveEnvironmentId();
  useSubscribeActiveCookieJarId();

  useSubscribeRecentRequests();
  useSubscribeRecentWorkspaces();
  useSubscribeRecentEnvironments();
  useSubscribeRecentCookieJars();

  useSyncWorkspaceRequestTitle();

  useHotKey('model.duplicate', () =>
    duplicateRequestOrFolderAndNavigate(jotaiStore.get(activeRequestAtom)),
  );
}
