import React, { useEffect, useState, useCallback } from 'react';
import { 
  Typography, 
  Card,
  Button, 
  Tabs, 
  Tab, 
  Paper, 
  IconButton, 
  Box, 
  useMediaQuery, 
  Divider, 
  Slider,
  Stack,
  TextField,
  Tooltip
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import SendIcon from '@mui/icons-material/Send';
import {
  ChevronLeft,
  ChevronRight,
  SwapHoriz,
  RestartAlt as ResetIcon,
} from '@mui/icons-material';
import PropagateLoader from "react-spinners/PropagateLoader";

import { Message } from './Message';
import { Document } from './Document';
import { DocumentViewerProps } from './DocumentTypes';
import MuiMarkdown from 'mui-markdown';

/**
 * 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> = ({
  generateResume,
  jobDescription,
  factCheck,
  resume,
  setResume,
  facts,
  setFacts,
  sx
}) => {
  // State for editing job description
  const [editJobDescription, setEditJobDescription] = useState<string | undefined>(jobDescription);
  // Processing state to show loading indicators
  const [processing, setProcessing] = useState<string | undefined>(undefined);
// Theme and responsive design setup
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
  
  // State for controlling which document is active on mobile
  const [activeTab, setActiveTab] = useState<number>(0);
  // State for controlling split ratio on desktop
  const [splitRatio, setSplitRatio] = useState<number>(0);
  
  /**
   * Reset processing state when resume is generated
   */
  useEffect(() => {
    if (resume !== undefined && processing === "resume") {
      setProcessing(undefined);
    }
  }, [processing, resume]);

  /**
   * Reset processing state when facts is generated
   */
  useEffect(() => {
    if (facts !== undefined && processing === "facts") {
      setProcessing(undefined);
    }
  }, [processing, facts]);

  /**
   * Trigger resume generation and update UI state
   */
  const triggerGeneration = useCallback((jobDescription: string | undefined) => {
    if (jobDescription === undefined) {
      setProcessing(undefined);
      setResume(undefined);
      setActiveTab(0);
      return;
    }
    setProcessing("resume");
    setTimeout(() => { setActiveTab(1); }, 250); // Switch to resume view on mobile
    generateResume(jobDescription);
  }, [generateResume, setProcessing, setActiveTab, setResume]);

  /**
   * Trigger fact check and update UI state
   */
  const triggerFactCheck = useCallback((resume: string | undefined) => {
    if (resume === undefined) {
      setProcessing(undefined);
      setResume(undefined);
      setFacts(undefined);
      setActiveTab(1);
      return;
    }
    setProcessing("facts");
    factCheck(resume);
    setTimeout(() => { setActiveTab(2); }, 250); // Switch to resume view on mobile
  }, [factCheck, setResume, setProcessing, setActiveTab, setFacts]);

  /**
   * Switch to resume tab when resume become available
   */
  useEffect(() => {
    if (resume !== undefined) {
      setTimeout(() => { setActiveTab(1); }, 250); // Switch to resume view on mobile
    }
  }, [resume]);

  /**
   * Switch to fact check tab when facts become available
   */
  useEffect(() => {
    if (facts !== undefined) {
      setTimeout(() => { setActiveTab(2); }, 250); // Switch to resume view on mobile
    }
  }, [facts]);

  /**
   * 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);
  };
  
  /**
   * Handle keyboard shortcuts
   */
  const handleKeyPress = (event: React.KeyboardEvent): void => {
    if (event.key === 'Enter' && event.ctrlKey) {
      triggerGeneration(editJobDescription || "");
    }
  };

  const renderJobDescriptionView = () => {
    const jobDescription = [];

    if (resume === undefined && processing === undefined) {
      jobDescription.push(
        <Document key="jobDescription" sx={{ display: "flex", flexGrow: 1 }} title="">
          <TextField
            variant="outlined"
            fullWidth
            multiline
            type="text"
            sx={{
              flex: 1,
              flexGrow: 1,
              maxHeight: '100%',
              overflow: 'auto',
            }}
            value={editJobDescription}
            onChange={(e) => setEditJobDescription(e.target.value)}
            onKeyDown={handleKeyPress}
            placeholder="Paste a job description, then click Generate..."
          />
        </Document>
      );
    } else {
      jobDescription.push(<MuiMarkdown key="jobDescription" >{editJobDescription}</MuiMarkdown>)
    }

    jobDescription.push(
      <Box key="jobActions" sx={{ display: "flex", justifyContent: "center", flexDirection: "row" }}>
        <IconButton
          sx={{ display: "flex", margin: 'auto 0px' }}
          size="large"
          edge="start"
          color="inherit"
          disabled={processing !== undefined}
          onClick={() => { setEditJobDescription(""); triggerGeneration(undefined); }}
        >
          <Tooltip title="Reset Job Description">
            <ResetIcon />
          </Tooltip>
        </IconButton>
        <Tooltip title="Generate">
          <Button
            sx={{ m: 1, gap: 1, flexGrow: 1 }}
            variant="contained"
            onClick={() => { triggerGeneration(editJobDescription); }}
          >
            Generate<SendIcon />
          </Button>
        </Tooltip>
      </Box>
    );

    return jobDescription;
  }

  /**
   * Renders the resume view with loading indicator
   */
  const renderResumeView = () => (
    <Box key="ResumeView" sx={{ display: "flex", flexDirection: "column", overflow: "auto", flexGrow: 1, flexBasis: 0 }}>
      <Document sx={{ display: "flex", flexGrow: 1 }} title="">
        {resume !== undefined && <Message message={resume} />}
      </Document>
      {processing === "resume" && (
        <Box sx={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          justifyContent: "center",
          mb: 1,
          height: "10px"
        }}>
          <PropagateLoader
            size="10px"
            loading={true}
            aria-label="Loading Spinner"
            data-testid="loader"
          />
          <Typography>Generating resume...</Typography>
        </Box>
      )}
      <ResumeActionCard
        resume={resume}
        processing={processing}
        triggerFactCheck={triggerFactCheck}
      />
    </Box>
  );

  /**
   * Renders the fact check view
   */
  const renderFactCheckView = () => (
    <Box key="FactView" sx={{ display: "flex", flexDirection: "column", overflow: "auto", flexGrow: 1, flexBasis: 0, p: 0 }}>
      <Document sx={{ display: "flex", flexGrow: 1 }} title="">
        {facts !== undefined && <Message message={facts} />}
      </Document>
      {processing === "facts" && (
        <Box sx={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          justifyContent: "center",
          mb: 1,
          height: "10px"
        }}>
          <PropagateLoader
            size="10px"
            loading={true}
            aria-label="Loading Spinner"
            data-testid="loader"
          />
          <Typography>Fact Checking resume...</Typography>
        </Box>
      )}
    </Box>
  );

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

    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" />
          {(resume !== undefined || processing === "resume") && <Tab value={1} label="Resume" />}
          {(facts !== undefined || processing === "facts") && <Tab value={2} label="Fact Check" />}
        </Tabs>

        {/* Document display area */}
        <Box sx={{ display: 'flex', flexDirection: 'column', flexGrow: 1, overflow: 'hidden', p: 0 }}>
          {getActiveMobileContent()}
        </Box>
      </Box>
    );
  }

  /**
   * Gets the appropriate content based on active state for Desktop
   */
  const getActiveDesktopContent = () => {
    /* Left panel - Job Description */
    const showResume = resume !== undefined || processing === "resume"
    const showFactCheck = facts !== undefined || processing === "facts"
    const otherRatio = showResume ? (100 - splitRatio / 2) : 100;
    const children = [];
    children.push(
      <Box key="JobDescription" sx={{ display: 'flex', flexDirection: 'column', width: `${otherRatio}%`, p: 0, flexGrow: 1, overflow: 'hidden' }}>
        {renderJobDescriptionView()}
      </Box>);

    /* Resume panel - conditionally rendered if resume defined, or processing is in progress */
    if (showResume) {
      children.push(
        <Box key="ResumeView" sx={{ display: 'flex', width: '100%', p: 0, flexGrow: 1, flexDirection: 'row' }}>
          <Divider orientation="vertical" flexItem />
          {renderResumeView()}
        </Box>
      );
    }

    /* Fact Check panel - conditionally rendered if facts defined, or processing is in progress */
    if (showFactCheck) {
      children.push(
        <Box key="FactCheckView" sx={{ display: 'flex', width: `${otherRatio}%`, p: 0, flexGrow: 1, flexDirection: 'row' }}>
          <Divider orientation="vertical" flexItem />
          {renderFactCheckView()}
        </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(Math.max(0, splitRatio - 10))}>
            <ChevronLeft />
          </IconButton>

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

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

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

    return (
      <Box sx={{ display: 'flex', flexGrow: 1, flexDirection: 'column', overflow: 'hidden', p: 0 }}>
        <Box sx={{ display: 'flex', flexGrow: 1, flexDirection: 'row', overflow: 'hidden', p: 0 }}>
          {children}
        </Box>
        {slider}
      </Box>
    )
  }

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


/**
 * Props for the ResumeActionCard component
 */
interface ResumeActionCardProps {
  resume: any;
  processing: string | undefined;
  triggerFactCheck: (resume: string | undefined) => void;
}

/**
 * Action card displayed underneath the resume with notes and fact check button
 */
const ResumeActionCard: React.FC<ResumeActionCardProps> = ({ resume, processing, triggerFactCheck }) => (
  <Box sx={{ display: "flex", justifyContent: "center", flexDirection: "column" }}>
    <Card sx={{ display: "flex", overflow: "auto", minHeight: "fit-content", p: 1, flexDirection: "column" }}>
      {resume !== undefined || processing === "resume" ? (
        <Typography>
          <b>NOTE:</b> As with all LLMs, hallucination is always a possibility. If the generated resume seems too good to be true, <b>Fact Check</b> or, expand the <b>LLM information for this query</b> section (at the end of the resume) and click the links in the <b>Top RAG</b> matches to view the relavent RAG source document to read the details. Or go back to 'Backstory' and ask a question.
        </Typography>
      ) : (
        <Typography>
          Once you click <b>Generate</b> under the <b>Job Description</b>, a resume will be generated based on the user's RAG content and the job description.
        </Typography>
      )}
    </Card>
    <Box sx={{ display: "flex", justifyContent: "center", flexDirection: "row", flexGrow: 1 }}>
      <IconButton
        sx={{ display: "flex", margin: 'auto 0px' }}
        size="large"
        edge="start"
        color="inherit"
        disabled={processing === "resume"}
        onClick={() => { triggerFactCheck(undefined); }}
      >
        <Tooltip title="Reset Resume">
          <ResetIcon />
        </Tooltip>
      </IconButton>
      <Tooltip title="Fact Check">
        <span style={{ display: "flex", flexGrow: 1 }}>
          <Button
            sx={{ m: 1, gap: 1, flexGrow: 1 }}
            variant="contained"
            disabled={processing === "facts"}
            onClick={() => { resume && triggerFactCheck(resume.content); }}
          >
            Fact Check<SendIcon />
          </Button>
        </span>
      </Tooltip>
    </Box>
  </Box>
);

export {
  DocumentViewer
};