import React, { useState, useCallback, useRef } from 'react';
import {
  Tabs,
  Tab,
  Paper,
  IconButton,
  Box,
  useMediaQuery,
  Divider,
  Slider,
  Stack,
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import {
  ChevronLeft,
  ChevronRight,
  SwapHoriz,
} from '@mui/icons-material';
import { SxProps, Theme } from '@mui/material';

import { SeverityType } from './Snack';

import { ChatQuery } from './Message';
import { MessageList, MessageData } from './Message';
import { SetSnackType } from './Snack';
import { Conversation } from './Conversation';

/**
 * Props for the DocumentViewer component
 * @interface DocumentViewerProps
 * @property {SxProps<Theme>} [sx] - Optional styling properties
 * @property {string} [connectionBase] - Base URL for fetch calls
 * @property {string} [sessionId] - Session ID
 * @property {SetSnackType} - setSnack UI callback
 */
export interface DocumentViewerProps {
  sx?: SxProps<Theme>;
  connectionBase: string;
  sessionId: string;
  setSnack: SetSnackType;
}
/**
 * DocumentViewer component
 * 
 * A responsive component that displays job descriptions, generated resumes and fact checks
 * with different layouts for mobile and desktop views.
 */
const DocumentViewer: React.FC<DocumentViewerProps> = ({
  sx,
  connectionBase,
  sessionId,
  setSnack
}) => {
  // State for editing job description
  const [hasJobDescription, setHasJobDescription] = useState<boolean>(false);
  const [hasResume, setHasResume] = useState<boolean>(false);
  const [hasFacts, setHasFacts] = useState<boolean>(false);
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
  const jobConversationRef = useRef<any>(null);
  const resumeConversationRef = useRef<any>(null);
  const factsConversationRef = useRef<any>(null);

  const [activeTab, setActiveTab] = useState<number>(0);
  const [splitRatio, setSplitRatio] = useState<number>(100);

  /**
   * Handle tab change for mobile view
   */
  const handleTabChange = (_event: React.SyntheticEvent, newValue: number): void => {
    setActiveTab(newValue);
  };

  /**
   * Adjust split ratio for desktop view
   */
  const handleSliderChange = (_event: Event, newValue: number | number[]): void => {
    setSplitRatio(newValue as number);
  };

  /**
   * Reset split ratio to default
   */
  const resetSplit = (): void => {
    setSplitRatio(50);
  };

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

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

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

  const filterJobDescriptionMessages = useCallback((messages: MessageList): MessageList => {
    if (messages === undefined || messages.length === 0) {
      return [];
    }

    let reduced = messages.filter((m, i) => {
      const keep = (m.metadata?.origin || m.origin || "no origin") === 'job_description';
      if ((m.metadata?.origin || m.origin || "no origin") === 'resume') {
        setHasResume(true);
      }
      // if (!keep) {
      //   console.log(`filterJobDescriptionMessages: ${i + 1} filtered:`, m);
      // } else {
      //   console.log(`filterJobDescriptionMessages: ${i + 1}:`, m);
      // }

      return keep;
    });

    if (reduced.length > 0) {
      // First message is always 'content'
      reduced[0].title = 'Job Description';
      reduced[0].role = 'content';
      setHasJobDescription(true);
    }

    /* If there is more than one message, it is user: "...JOB_DESCRIPTION...", assistant: "...stored..."
     * which means a resume has been generated. */
    if (reduced.length > 1) {
      setHasResume(true);
    }

    /* Filter out any messages which the server injected for state management */
    reduced = reduced.filter(m => m.display !== "hide");

    return reduced;
  }, [setHasJobDescription, setHasResume]);

  const filterResumeMessages = useCallback((messages: MessageList): MessageList => {
    if (messages === undefined || messages.length === 0) {
      return [];
    }

    let reduced = messages.filter((m, i) => {
      const keep = (m.metadata?.origin || m.origin || "no origin") === 'resume';
      if ((m.metadata?.origin || m.origin || "no origin") === 'fact_check') {
        setHasFacts(true);
      }
      // if (!keep) {
      //   console.log(`filterResumeMessages: ${i + 1} filtered:`, m);
      // } else {
      //   console.log(`filterResumeMessages: ${i + 1}:`, m);
      // }
      return keep;
    });

    /* If there is more than one message, it is user: "...JOB_DESCRIPTION...", assistant: "...RESUME..."
     * which means a resume has been generated. */
    if (reduced.length > 1) {
      /* Remove the assistant message from the UI */
      if (reduced[0].role === "user") {
        reduced.splice(0, 1);
      }
    }

    /* If Fact Check hasn't occurred yet and there is still more than one message, 
     * facts have have been generated. */
    if (!hasFacts && reduced.length > 1) {
      setHasFacts(true);
    }

    /* Filter out any messages which the server injected for state management */
    reduced = reduced.filter(m => m.display !== "hide");

    /* If there are any messages, there is a resume */
    if (reduced.length > 0) {
      // First message is always 'content'
      reduced[0].title = 'Resume';
      reduced[0].role = 'content';
      setHasResume(true);
    }

    return reduced;
  }, [setHasResume, hasFacts, setHasFacts]);

  const filterFactsMessages = useCallback((messages: MessageList): MessageList => {
    if (messages === undefined || messages.length === 0) {
      return [];
    }
    // messages.forEach((m, i) => console.log(`filterFactsMessages: ${i + 1}:`, m))

    const reduced = messages.filter(m => {
      return (m.metadata?.origin || m.origin || "no origin") === 'fact_check';
    });

    /* If there is more than one message, it is user: "Fact check this resume...", assistant: "...FACT CHECK..."
     * which means facts have been generated. */
    if (reduced.length > 1) {
      /* Remove the user message from the UI */
      if (reduced[0].role === "user") {
        reduced.splice(0, 1);
      }
      // First message is always 'content'
      reduced[0].title = 'Fact Check';
      reduced[0].role = 'content';
      setHasFacts(true);
    }

    return reduced;
  }, [setHasFacts]);

  const jobResponse = useCallback((message: MessageData): MessageData => {
    console.log('onJobResponse', message);
    setHasResume(true);
    return message;
  }, []);

  const resumeResponse = useCallback((message: MessageData): MessageData => {
    console.log('onResumeResponse', message);
    setHasFacts(true);
    return message;
  }, [setHasFacts]);

  const factsResponse = useCallback((message: MessageData): MessageData => {
    console.log('onFactsResponse', message);
    return message;
  }, []);

  const renderJobDescriptionView = useCallback((small: boolean) => {
    const jobDescriptionQuestions = [
      <Box sx={{ display: "flex", flexDirection: small ? "column" : "row" }}>
        <ChatQuery text="What are the key skills necessary for this position?" submitQuery={handleJobQuery} />
        <ChatQuery text="How much should this position pay (accounting for inflation)?" submitQuery={handleJobQuery} />
      </Box>,
    ];

    if (!hasJobDescription) {
      return <Conversation
        ref={jobConversationRef}
        {...{
          type: "job_description",
          actionLabel: "Generate Resume",
          prompt: "Paste a job description, then click Generate...",
          multiline: true,
          messageFilter: filterJobDescriptionMessages,
          onResponse: jobResponse,
          sessionId,
          connectionBase,
          setSnack,
        }}
      />

    } else {
      return <Conversation
        ref={jobConversationRef}
        {...{
          type: "job_description",
          actionLabel: "Send",
          prompt: "Ask a question about this job description...",
          messageFilter: filterJobDescriptionMessages,
          defaultPrompts: jobDescriptionQuestions,
          onResponse: jobResponse,
          sessionId,
          connectionBase,
          setSnack,
        }}
      />
    }
  }, [connectionBase, filterJobDescriptionMessages, hasJobDescription, sessionId, setSnack, jobResponse]);

  /**
   * Renders the resume view with loading indicator
   */
  const renderResumeView = useCallback((small: boolean) => {
    const resumeQuestions = [
      <Box sx={{ display: "flex", flexDirection: small ? "column" : "row" }}>
        <ChatQuery text="Is this resume a good fit for the provided job description?" submitQuery={handleResumeQuery} />
        <ChatQuery text="Provide a more concise resume." submitQuery={handleResumeQuery} />
      </Box>,
    ];

    if (!hasFacts) {
      return <Conversation
        ref={resumeConversationRef}
        {...{
          actionLabel: "Fact Check",
          multiline: true,
          type: "resume",
          messageFilter: filterResumeMessages,
          onResponse: resumeResponse,
          sessionId,
          connectionBase,
          setSnack,
        }}
      />
    } else {
      return <Conversation
        ref={resumeConversationRef}
        {...{
          type: "resume",
          actionLabel: "Send",
          prompt: "Ask a question about this job resume...",
          messageFilter: filterResumeMessages,
          defaultPrompts: resumeQuestions,
          onResponse: resumeResponse,
          sessionId,
          connectionBase,
          setSnack,
        }}
      />
    }
  }, [connectionBase, filterResumeMessages, hasFacts, sessionId, setSnack, resumeResponse]);

  /**
   * Renders the fact check view
   */
  const renderFactCheckView = useCallback((small: boolean) => {
    const factsQuestions = [
      <Box sx={{ display: "flex", flexDirection: small ? "column" : "row" }}>
        <ChatQuery text="Rewrite the resume to address any discrepancies." submitQuery={handleFactsQuery} />
      </Box>,
    ];

    return <Conversation
      ref={factsConversationRef}
      {...{
        type: "fact_check",
        actionLabel: "Send",
        prompt: "Ask a question about any discrepencies...",
        messageFilter: filterFactsMessages,
        defaultPrompts: factsQuestions,
        onResponse: factsResponse,
        sessionId,
        connectionBase,
        setSnack,
      }}
    />
  }, [connectionBase, sessionId, setSnack, factsResponse, filterFactsMessages]);

  /**
 * Gets the appropriate content based on active state for Desktop
 */
  const getActiveDesktopContent = useCallback(() => {
    /* Left panel - Job Description */
    const showResume = hasResume
    const showFactCheck = hasFacts
    const ratio = 75 + 25 * splitRatio / 100;
    const otherRatio = showResume ? ratio / (hasFacts ? 3 : 2) : 100;
    const resumeRatio = 100 - otherRatio * (hasFacts ? 2 : 1);
    const children = [];
    children.push(
      <Box key="JobDescription" className="ChatBox" sx={{ display: 'flex', flexDirection: 'column', minWidth: `${otherRatio}%`, width: `${otherRatio}%`, maxWidth: `${otherRatio}%`, p: 0, flexGrow: 1, overflowY: 'auto' }}>
        {renderJobDescriptionView(false)}
      </Box>);

    /* Resume panel - conditionally rendered if resume defined, or processing is in progress */
    if (showResume) {
      children.push(
        <Box key="ResumeView" className="ChatBox" sx={{ display: 'flex', flexDirection: 'column', minWidth: `${resumeRatio}%`, width: `${resumeRatio}%`, maxWidth: `${resumeRatio}%`, p: 0, flexGrow: 1, overflowY: 'auto' }}>
          <Divider orientation="vertical" flexItem />
          {renderResumeView(false)}
        </Box>
      );
    }

    /* Fact Check panel - conditionally rendered if facts defined, or processing is in progress */
    if (showFactCheck) {
      children.push(
        <Box key="FactCheckView" className="ChatBox" sx={{ display: 'flex', flexDirection: 'column', minWidth: `${otherRatio}%`, width: `${otherRatio}%`, maxWidth: `${otherRatio}%`, p: 0, flexGrow: 1, overflowY: 'auto' }}>
          <Divider orientation="vertical" flexItem />
          {renderFactCheckView(false)}
        </Box>
      );
    }

    /* Split control panel - conditionally rendered if either facts or resume is set */
    let slider = <Box key="slider"></Box>;
    if (showResume || showFactCheck) {
      slider = (
        <Paper key="slider" sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Stack direction="row" spacing={2} alignItems="center" sx={{ width: '60%' }}>
            <IconButton onClick={() => setSplitRatio(s => Math.max(0, s - 10))}>
              <ChevronLeft />
            </IconButton>

            <Slider
              value={splitRatio}
              onChange={handleSliderChange}
              aria-label="Split ratio"
              min={0}
              max={100}
            />

            <IconButton onClick={() => setSplitRatio(s => Math.min(100, s + 10))}>
              <ChevronRight />
            </IconButton>

            <IconButton onClick={resetSplit}>
              <SwapHoriz />
            </IconButton>
          </Stack>
        </Paper>
      );
    }

    return (
      <Box sx={{ ...sx, display: 'flex', flexGrow: 1, flexDirection: 'column', p: 0 }}>
        <Box sx={{ display: 'flex', flexGrow: 1, flexDirection: 'row', overflow: 'hidden', p: 0 }}>
          {children}
        </Box>
        {slider}
      </Box>
    )
  }, [renderFactCheckView, renderJobDescriptionView, renderResumeView, splitRatio, sx, hasFacts, hasResume]);

  // Render mobile view
  if (isMobile) {
    /**
     * Gets the appropriate content based on active tab
     */
    const getActiveMobileContent = () => {
      switch (activeTab) {
        case 0:
          return renderJobDescriptionView(true);
        case 1:
          return renderResumeView(true);
        case 2:
          return renderFactCheckView(true);
        default:
          return renderJobDescriptionView(true);
      }
    };

    return (
      <Box sx={{ display: 'flex', flexDirection: 'column', flexGrow: 1, ...sx }}>
        {/* Tabs */}
        <Tabs
          value={activeTab}
          onChange={handleTabChange}
          variant="fullWidth"
          sx={{ bgcolor: 'background.paper' }}
        >
          <Tab value={0} label="Job Description" />
          {hasResume && <Tab value={1} label="Resume" />}
          {hasFacts && <Tab value={2} label="Fact Check" />}
        </Tabs>

        {/* Document display area */}
        <Box sx={{ display: 'flex', flexDirection: 'column', flexGrow: 1, p: 0, width: "100%", ...sx }}>
          {getActiveMobileContent()}
        </Box>
      </Box>
    );
  }

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', flexGrow: 1, width: "100%", ...sx }}>
      {getActiveDesktopContent()}
    </Box>
  );
};

interface ResumeBuilderProps {
  connectionBase: string,
  sessionId: string | undefined,
  setSnack: (message: string, severity?: SeverityType) => void,
};

const ResumeBuilder = ({ connectionBase, sessionId, setSnack }: ResumeBuilderProps) => {
  if (sessionId === undefined) {
    return (<></>);
  }

  return (
    <Box className="DocBox">
      <Box className="Conversation" sx={{ p: 0, pt: 1 }}>
        <DocumentViewer sx={{
          p: 0,
          m: 0,
          display: "flex",
          flexGrow: 1,
          overflowY: "auto",
          flexDirection: "column",
          height: "calc(0vh - 0px)", // Hack to make the height work
        }} {...{ setSnack, connectionBase, sessionId }} />
      </Box>
    </Box>
  );
}

export type {
  ResumeBuilderProps
};

export {
  ResumeBuilder
};

