import React, { ReactElement, JSXElementConstructor, useState, useEffect, useRef, useCallback, useMemo } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import Card from '@mui/material/Card';
import { styled } from '@mui/material/styles';
import Avatar from '@mui/material/Avatar';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import Tooltip from '@mui/material/Tooltip';
import AppBar from '@mui/material/AppBar';
import Drawer from '@mui/material/Drawer';
import Toolbar from '@mui/material/Toolbar';
import SettingsIcon from '@mui/icons-material/Settings';
import IconButton from '@mui/material/IconButton';
import Box from '@mui/material/Box';
import CssBaseline from '@mui/material/CssBaseline';
import MenuIcon from '@mui/icons-material/Menu';
import { useTheme } from '@mui/material/styles';
import { SxProps } from '@mui/material';


import { ResumeBuilder } from './ResumeBuilder';
import { Message, ChatQuery, MessageList } from './Message';
import { Snack, SeverityType } from './Snack';
import { VectorVisualizer } from './VectorVisualizer';
import { Controls } from './Controls';
import { Conversation, ConversationHandle } from './Conversation';
import { Scrollable } from './AutoScroll';
import { BackstoryTab } from './BackstoryTab';

import './App.css';
import './Conversation.css';

import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

import MuiMarkdown from 'mui-markdown';

const getConnectionBase = (loc: any): string => {
  if (!loc.host.match(/.*battle-linux.*/)) {
    return loc.protocol + "//" + loc.host;
  } else {
    return loc.protocol + "//battle-linux.ketrenos.com:8912";
  }
}

interface TabProps {
  label?: string,
  path: string,
  tabProps?: {
    label?: string,
    sx?: SxProps,
    icon?: string | ReactElement<unknown, string | JSXElementConstructor<any>> | undefined,
    iconPosition?: "bottom" | "top" | "start" | "end" | undefined
  }
};

const App = () => {
  const [sessionId, setSessionId] = useState<string | undefined>(undefined);
  const [connectionBase,] = useState<string>(getConnectionBase(window.location))
  const [menuOpen, setMenuOpen] = useState(false);
  const [isMenuClosing, setIsMenuClosing] = useState(false);
  const [activeTab, setActiveTab] = useState<number>(0);
  const [about, setAbout] = useState<string>("");
  const isDesktop = useMediaQuery('(min-width:650px)');
  const prevIsDesktopRef = useRef<boolean>(isDesktop);
  const chatRef = useRef<ConversationHandle>(null);
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
  const snackRef = useRef<any>(null);

  useEffect(() => {
    if (prevIsDesktopRef.current === isDesktop)
      return;
    
    if (menuOpen) {
      setMenuOpen(false);
    }
    
    prevIsDesktopRef.current = isDesktop;
  }, [isDesktop, setMenuOpen, menuOpen])

  const setSnack = useCallback((message: string, severity?: SeverityType) => {
    snackRef.current?.setSnack(message, severity);
  }, [snackRef]);

  // Get the About markdown
  useEffect(() => {
    if (about !== "") {
      return;
    }
    const fetchAbout = async () => {
      try {
        const response = await fetch("/docs/about.md", {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
          },
        });
        if (!response.ok) {
          throw Error("/docs/about.md not found");
        } 
        const data = await response.text();
        setAbout(data);
      } catch (error: any) {
        console.error('Error obtaining About content information:', error);
        setAbout("No information provided.");
      };
    };

    fetchAbout();
  }, [about, setAbout])


  const handleSubmitChatQuery = (query: string) => {
    console.log(`handleSubmitChatQuery: ${query} -- `, chatRef.current ? ' sending' : 'no handler');
    chatRef.current?.submitQuery(query);
    setActiveTab(0);
  };


  const tabs: TabProps[] = useMemo(() => {
    const backstoryPreamble: MessageList = [
      {
        role: 'content',
        title: 'Welcome to Backstory',
        content: `
  Backstory is a RAG enabled expert system with access to real-time data running self-hosted
  (no cloud) versions of industry leading Large and Small Language Models (LLM/SLMs).
  It was written by James Ketrenos in order to provide answers to
  questions potential employers may have about his work history.
  
  What would you like to know about James?
  `
      }
    ];

    const backstoryQuestions = [
      <Box sx={{ display: "flex", flexDirection: isMobile ? "column" : "row" }}>
        <ChatQuery text="What is James Ketrenos' work history?" submitQuery={handleSubmitChatQuery} />
        <ChatQuery text="What programming languages has James used?" submitQuery={handleSubmitChatQuery} />
        <ChatQuery text="What are James' professional strengths?" submitQuery={handleSubmitChatQuery} />
        <ChatQuery text="What are today's headlines on CNBC.com?" submitQuery={handleSubmitChatQuery} />
      </Box>,
      <Box sx={{ p: 1 }}>
        <MuiMarkdown>
          As with all LLM interactions, the results may not be 100% accurate. If you have questions about my career,
          I'd love to hear from you. You can send me an email at **james_backstory@ketrenos.com**.
        </MuiMarkdown>
      </Box>
    ];

    const tabSx = { flexGrow: 1, fontSize: '1rem' };

    return [{
      label: "",
      path: "",
      tabProps: {
        label: "Backstory",
        sx: tabSx,
        icon:
          <Avatar sx={{
            width: 24,
            height: 24
          }}
            variant="rounded"
            alt="Backstory logo"
            src="/logo192.png" />,
        iconPosition: "start"
      },
      children: (
        <Scrollable
          sx={{
            maxWidth: "1024px",
            height: "calc(100vh - 72px)",
          }}
        >
          <Conversation
            ref={chatRef}
            {...{
              type: "chat",
              prompt: "What would you like to know about James?",
              sessionId,
              connectionBase,
              setSnack,
              preamble: backstoryPreamble,
              defaultPrompts: backstoryQuestions
            }}
          />
        </Scrollable>
      )
    }, {
        label: "Resume Builder",
        path: "resume-builder",
        children: (
          <ResumeBuilder sx={{
            margin: "0 auto",
            height: "calc(100vh - 72px)",
            overflow: "auto",
            backgroundColor: "#F5F5F5",
            display: "flex",
            flexGrow: 1
          }} {...{ setSnack, connectionBase, sessionId }}
          />
        )
      }, {
        label: "Context Visualizer",
        path: "context-visualizer",
        children:
          <Scrollable
            sx={{
              maxWidth: "1024px",
              height: "calc(100vh - 72px)",
            }}
          >
            <VectorVisualizer sx={{ p: 1 }} {...{ connectionBase, sessionId, setSnack }} />
          </Scrollable>
      }, {
        label: "About",
        path: "about",
        children: (
          <Scrollable
            sx={{
              maxWidth: "1024px",
              height: "calc(100vh - 72px)",
              flexDirection: "column",
              margin: "0 auto",
              p: 1,
            }}
          >
            <Message
              {...{
                sx: {
                  display: 'flex',
                  flexDirection: 'column',
                  p: 1,
                  m: 0,
                  flexGrow: 0,
                },
                message: { role: 'content', title: "About Backstory", content: about },
                submitQuery: handleSubmitChatQuery,
                connectionBase,
                sessionId,
                setSnack
              }} />
            <Box sx={{ display: "flex", flexGrow: 1, p: 0, m: 0 }} />
          </Scrollable>
        )
      }, {
        path: "settings",
        tabProps: {
          sx: { flexShrink: 1, flexGrow: 0, fontSize: '1rem' },
          icon: <SettingsIcon />
        },
        children: (
          <Box className="ChatBox">
            {sessionId !== undefined &&
              <Controls {...{ sessionId, setSnack, connectionBase }} />
            }
          </Box >
        )
      }];
  }, [about, connectionBase, sessionId, setSnack, isMobile]);

  useEffect(() => {
    const url = new URL(window.location.href);
    const pathParts = url.pathname.split('/').filter(Boolean); // [path, sessionId]

    const fetchSession = async () => {
      try {
        const response = await fetch(connectionBase + `/api/context`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
        });

        if (!response.ok) {
          throw Error("Server is temporarily down.");
        }
        const data = await response.json();
        setSessionId(data.id);

        const newPath = `/${data.id}`;
        window.history.replaceState({}, '', newPath);
      } catch (error: any) {
        console.error(error);
        setSnack("Server is temporarily down", "error");
      }
    };

    if (pathParts.length < 1) {
      console.log("No session id or path -- creating new session");
      fetchSession();
    } else {
      const currentPath = pathParts.length < 2 ? '' : pathParts[0];
      const session = pathParts.length < 2 ? pathParts[0] : pathParts[1];
      let tabIndex = tabs.findIndex((tab) => tab.path === currentPath);
      if (-1 === tabIndex) {
        console.log(`Invalid path "${currentPath}" -- redirecting to default`);
        tabIndex = 0;
      }
      setSessionId(session);
      setActiveTab(tabIndex);
    }
  }, [setSessionId, connectionBase, setSnack, tabs]);

  const handleMenuClose = () => {
    setIsMenuClosing(true);
    setMenuOpen(false);
  };

  const handleMenuTransitionEnd = () => {
    setIsMenuClosing(false);
  };

  const handleMenuToggle = () => {
    if (!isMenuClosing) {
      setMenuOpen(!menuOpen);
    }
  };

  const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
    if (newValue > tabs.length) {
      return;
    }
    setActiveTab(newValue);
    const tabPath = tabs[newValue].path;
    if (tabPath) {
      window.history.pushState({}, '', `/${tabPath}/${sessionId}`);
    } else {
      window.history.pushState({}, '', `/${sessionId}`);
    }
    handleMenuClose();
  };

  useEffect(() => {
    const handlePopState = () => {
      const url = new URL(window.location.href);
      const pathParts = url.pathname.split('/').filter(Boolean);
      const currentPath = pathParts.length < 2 ? '' : pathParts[0];
      const session = pathParts.length < 2 ? pathParts[0] : pathParts[1];

      let tabIndex = tabs.findIndex((tab) => tab.path === currentPath);
      if (-1 === tabIndex) {
        console.log(`Invalid path "${currentPath}" -- redirecting to default`);
        tabIndex = 0;
      }
      setSessionId(session);
      setActiveTab(tabIndex);
    };

    window.addEventListener('popstate', handlePopState);
    return () => window.removeEventListener('popstate', handlePopState);
  }, [setSessionId, tabs]);

  /* toolbar height is 64px + 8px margin-top */
  const Offset = styled('div')(() => ({ minHeight: '72px', height: '72px' }));

  return (
    <Box className="App"
      sx={{ display: 'flex', flexDirection: 'column' }}>
      <CssBaseline />
      <AppBar
        position="fixed"
        sx={{
          zIndex: (theme) => theme.zIndex.drawer + 1,
          maxWidth: "100vw"
        }}
      >
        <Toolbar>
          <Box sx={{ display: "flex", flexGrow: 1, flexDirection: "row" }}>
            {!isDesktop &&
              <Box sx={{ display: "flex", flexGrow: 1, flexDirection: "row" }}>
                <IconButton
                  sx={{ display: "flex", margin: 'auto 0px' }}
                  size="large"
                  edge="start"
                  color="inherit"
                  onClick={handleMenuToggle}
                >
                  <Tooltip title="Navigation">
                    <MenuIcon />
                  </Tooltip>
                </IconButton>
                <Tooltip title="Backstory">
                  <Box
                    sx={{ m: 1, gap: 1, display: "flex", flexDirection: "row", alignItems: "center", fontWeight: "bold", fontSize: "1.0rem", cursor: "pointer" }}
                    onClick={() => { setActiveTab(0); setMenuOpen(false); }}
                  >
                    <Avatar sx={{
                      width: 24,
                      height: 24
                    }}
                      variant="rounded"
                      alt="Backstory logo"
                      src="/logo192.png" />
                    BACKSTORY
                  </Box>
                </Tooltip>
              </Box>
            }

            {menuOpen === false && isDesktop &&
              <Tabs sx={{ display: "flex", flexGrow: 1 }}
                value={activeTab}
                indicatorColor="secondary"
                textColor="inherit"
                variant="fullWidth"
                allowScrollButtonsMobile
                onChange={handleTabChange}
                aria-label="Backstory navigation">
                {tabs.map((tab, index) => <Tab key={index} value={index} label={tab.label} {...tab.tabProps} />)}
              </Tabs>
            }
          </Box>
        </Toolbar>

      </AppBar>

      <Offset />

      <Box
        sx={{ display: "flex", flexGrow: 1, flexDirection: "column" }}
      >
        <Box
          component="nav"
          aria-label="mailbox folders"
        >
          <Drawer
            container={window.document.body}
            variant="temporary"
            open={menuOpen}
            onTransitionEnd={handleMenuTransitionEnd}
            onClose={handleMenuClose}
            sx={{
              display: 'block',
              '& .MuiDrawer-paper': { boxSizing: 'border-box' },
            }}
            slotProps={{
              root: {
                keepMounted: true, // Better open performance on mobile.
              },
            }}
          >
            <Toolbar />
            <Card className="MenuCard">
              <Tabs sx={{ display: "flex", flexGrow: 1 }}
                orientation="vertical"
                value={activeTab}
                indicatorColor="secondary"
                textColor="inherit"
                variant="scrollable"
                allowScrollButtonsMobile
                onChange={handleTabChange}
                aria-label="Backstory navigation">
                {tabs.map((tab, index) => <Tab key={index} value={index} label={tab.label} {...tab.tabProps} />)}
              </Tabs>
            </Card>
          </Drawer>
        </Box>
        {
          tabs.map((tab: any, i: number) =>
            <BackstoryTab key={i} active={i === activeTab}>{tab.children}</BackstoryTab>
          )
        }
      </Box>

      <Snack
        ref={snackRef}
      />
    </Box >
  );
};

export default App;