import React, { useState, useEffect, useRef, useCallback } 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 Snackbar, { SnackbarCloseReason } from '@mui/material/Snackbar';
import Alert from '@mui/material/Alert';
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 { ResumeBuilder } from './ResumeBuilder';
import { Message, ChatQuery, MessageList, MessageData } from './Message';
import { SeverityType } from './Snack';
import { VectorVisualizer } from './VectorVisualizer';
import { Controls } from './Controls';
import { Conversation, ConversationHandle } from './Conversation';

import './App.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 TabPanelProps {
  children?: React.ReactNode;
  index: number;
  tab: number;
}

function CustomTabPanel(props: TabPanelProps) {
  const { children, tab, index, ...other } = props;

  return (
    <div
      className="TabPanel"
      role="tabpanel"
      style={{ "display": tab === index ? "flex": "none" }}
      id={`tabpanel-${index}`}
      aria-labelledby={`tab-${index}`}
      {...other}
    >
      {tab === index && children}
    </div>
  );
}

const App = () => {
  const conversationRef = useRef<any>(null);
  const [processing, setProcessing] = useState(false);
  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 [snackOpen, setSnackOpen] = useState(false);
  const [snackMessage, setSnackMessage] = useState("");
  const [snackSeverity, setSnackSeverity] = useState<SeverityType>("success");
  const [tab, setTab] = useState<number>(0);
  const [about, setAbout] = useState<string>("");
  const [resume, setResume] = useState<MessageData | undefined>(undefined);
  const [facts, setFacts] = useState<MessageData | undefined>(undefined);
  const isDesktop = useMediaQuery('(min-width:650px)');
  const prevIsDesktopRef = useRef<boolean>(isDesktop);
  const chatRef = useRef<ConversationHandle>(null);

  // Set the snack pop-up and open it
  const setSnack = useCallback((message: string, severity: SeverityType = "success") => {
    setSnackMessage(message);
    setSnackSeverity(severity);
    setSnackOpen(true);
  }, []);

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

  // 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);
  };

  const chatPreamble: MessageList = [
    {
      role: 'info',
      content: `
# Welcome to Backstory

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 chatQuestions = [
    <Box sx={{ display: "flex", flexDirection: "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>,
    <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>
  ];


  // Extract the sessionId from the URL if present, otherwise
  // request a sessionId from the server.
  useEffect(() => {
    const url = new URL(window.location.href);
    const pathParts = url.pathname.split('/').filter(Boolean);

    if (!pathParts.length) {
      console.log("No session id -- creating a new session")
      fetch(connectionBase + `/api/context`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
      })
        .then(response => response.json())
        .then(data => {
          console.log(`Session id: ${data.id} -- returned from server`)
          setSessionId(data.id);
          window.history.replaceState({}, '', `/${data.id}`);
        })
        .catch(error => console.error('Error generating session ID:', error));
    } else {
      console.log(`Session id: ${pathParts[0]} -- existing session`)
      setSessionId(pathParts[0]);
    }

  }, [setSessionId, connectionBase]);

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

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

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

  const settingsPanel = (
    <>
      {sessionId !== undefined &&
        <Controls {...{ sessionId, setSnack, connectionBase }} />}
    </>
  );

  const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
    setTab(newValue);
    handleMenuClose();
  };


  const menuDrawer = (
    <Card className="MenuCard">
      <Tabs sx={{ display: "flex", flexGrow: 1 }}
        orientation="vertical"
        value={tab}
        indicatorColor="secondary"
        textColor="inherit"
        variant="scrollable"
        allowScrollButtonsMobile
        onChange={handleTabChange}
        aria-label="Backstory navigation">
        <Tab sx={{ fontSize: '1rem' }} label="Backstory"
          value={0}
          icon={
            <Avatar sx={{
              width: 24,
              height: 24
            }}
              variant="rounded"
              alt="Backstory logo"
              src="/logo192.png" />
          }
          iconPosition="start" />
          <Tab
            value={1}
            sx={{ fontSize: '1rem' }} wrapped
            label="Resume Builder"
          />
          <Tab
            value={2}
            sx={{ fontSize: '1rem' }} wrapped
            label="Context Visualizer"
          />
        <Tab
          value={3}
          sx={{ fontSize: '1rem' }} label="About" />
        <Tab
          value={4}
          sx={{ fontSize: '1rem' }} icon={<SettingsIcon />} />
      </Tabs>
    </Card>
  );

  const handleSnackClose = (
    event: React.SyntheticEvent | Event,
    reason?: SnackbarCloseReason,
  ) => {
    if (reason === 'clickaway') {
      return;
    }

    setSnackOpen(false);
  };

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

  return (
    <Box className="App" sx={{ display: 'flex', flexDirection: 'column', height: '100dvh' }}>
      <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={() => { setTab(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={tab}
                indicatorColor="secondary"
                textColor="inherit"
                variant="fullWidth"
                allowScrollButtonsMobile
                onChange={handleTabChange}
                aria-label="Backstory navigation">
                <Tab sx={{ fontSize: '1rem' }} label="Backstory"
                  value={0}
                  icon={
                    <Avatar sx={{
                      width: 24,
                      height: 24
                    }}
                      variant="rounded"
                      alt="Backstory logo"
                      src="/logo192.png" />
                  }
                  iconPosition="start" />
                <Tab
                  value={1}
                  sx={{ fontSize: '1rem' }} wrapped
                  label="Resume Builder"
                />
                <Tab
                  value={2}
                  sx={{ fontSize: '1rem' }} wrapped
                  label="Context Visualizer"
                />
                <Tab
                  value={3}
                  sx={{ fontSize: '1rem' }} label="About" />
                <Tab
                  value={4}
                  sx={{ flexShrink: 1, flexGrow: 0, fontSize: '1rem' }} icon={<SettingsIcon />} />
              </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 />
            {menuDrawer}
          </Drawer>
        </Box>
        
        <CustomTabPanel tab={tab} index={0}>        
          <Box component="main" sx={{ flexGrow: 1, overflow: 'auto' }} className="ChatBox" ref={conversationRef}>
            <Conversation
              ref={chatRef}
              {...{
                type: "chat",
                prompt: "What would you like to know about James?",
                sessionId,
                connectionBase,
                setSnack,
                preamble: chatPreamble,
                defaultPrompts: chatQuestions
              }}
            />
          </Box>
        </CustomTabPanel>

        <CustomTabPanel tab={tab} index={1}>
          <ResumeBuilder {...{ facts, setFacts, resume, setResume, processing, setProcessing, setSnack, connectionBase: connectionBase, sessionId }} />
        </CustomTabPanel>

        <CustomTabPanel tab={tab} index={2}>
          <Box className="ChatBox">
            <Box className="Conversation">
              <VectorVisualizer {...{ connectionBase, sessionId, setSnack }} />
            </Box>
          </Box>
        </CustomTabPanel>

        <CustomTabPanel tab={tab} index={3}>
          <Box className="ChatBox">
            <Box className="Conversation">
              <Message {...{ message: { role: 'assistant', content: about }, submitQuery: handleSubmitChatQuery, connectionBase, sessionId, setSnack }} />
            </Box>
          </Box>
        </CustomTabPanel>
        
        <CustomTabPanel tab={tab} index={4}>
          <Box className="ChatBox">
            <Box className="Conversation">
              { settingsPanel }
            </Box>
          </Box>
        </CustomTabPanel>

      </Box>

      <Snackbar open={snackOpen} autoHideDuration={(snackSeverity === "success" || snackSeverity === "info") ? 1500 : 6000} onClose={handleSnackClose}>
        <Alert
          onClose={handleSnackClose}
          severity={snackSeverity}
          variant="filled"
          sx={{ width: '100%' }}
        >
          {snackMessage}
        </Alert>
      </Snackbar>
    </Box >
  );
};

export default App;