import React, { useState, useEffect, useCallback, useRef } from 'react';
import { 
  Box, 
  Stepper, 
  Step, 
  StepLabel, 
  Button, 
  Typography, 
  Paper, 
  useTheme,
  Snackbar,
  Alert,
  Tabs,
  Tab,
  Avatar,
  useMediaQuery,
  Divider,
} from '@mui/material';
import {
  Add,
  WorkOutline,
} from '@mui/icons-material';
import PersonIcon from '@mui/icons-material/Person';
import WorkIcon from '@mui/icons-material/Work';
import AssessmentIcon from '@mui/icons-material/Assessment';
import { JobMatchAnalysis } from 'components/JobMatchAnalysis';
import { Candidate, Job, SkillAssessment } from "types/types";
import { useNavigate } from 'react-router-dom';
import { BackstoryPageProps } from 'components/BackstoryTab';
import { useAuth } from 'hooks/AuthContext';
import { useAppState, useSelectedCandidate, useSelectedJob } from 'hooks/GlobalContext';
import { CandidateInfo } from 'components/ui/CandidateInfo';
import { ComingSoon } from 'components/ui/ComingSoon';
import { LoginRequired } from 'components/ui/LoginRequired';
import { Scrollable } from 'components/Scrollable';
import { CandidatePicker } from 'components/ui/CandidatePicker';
import { JobPicker } from 'components/ui/JobPicker';
import { JobCreator } from 'components/JobCreator';
import { LoginRestricted } from 'components/ui/LoginRestricted';
import JsonView from '@uiw/react-json-view';
import { ResumeGenerator } from 'components/ResumeGenerator';
import { JobInfo } from 'components/ui/JobInfo';

function WorkAddIcon() {
  return (
    <Box position="relative" display="inline-flex"
      sx={{
        lineHeight: "30px",
        mb: "6px",
      }}
    >
      <WorkOutline sx={{ fontSize: 24 }} />
      <Add
        sx={{
          position: 'absolute',
          bottom: -2,
          right: -2,
          fontSize: 14,
          bgcolor: 'background.paper',
          borderRadius: '50%',
          boxShadow: 1,
        }}
        color="primary"
      />
    </Box>
  );
}

interface AnalysisState {
  job: Job | null;
  candidate: Candidate | null;
  analysis: SkillAssessment[] | null;
  resume: string | null;
};

interface Step {
  index: number;
  label: string;
  requiredState: string[];
  title: string;
  icon: React.ReactNode;
};

const initialState: AnalysisState = {
  job: null,
  candidate: null,
  analysis: null,
  resume: null,
};

// Steps in our process
const steps: Step[] = [
  { requiredState: [], title: 'Job Selection', icon: <WorkIcon /> },
  { requiredState: ['job'], title: 'Select Candidate', icon: <PersonIcon /> },
  { requiredState: ['job', 'candidate'], title: 'Job Analysis', icon: <WorkIcon /> },
  { requiredState: ['job', 'candidate', 'analysis'], title: 'Generated Resume', icon: <AssessmentIcon /> }
].map((item, index) => { return { ...item, index, label: item.title.toLowerCase().replace(/ /g, '-') } });

const capitalize = (str: string) => {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

// Main component
const JobAnalysisPage: React.FC<BackstoryPageProps> = (props: BackstoryPageProps) => {
  const theme = useTheme();
  const { user, guest } = useAuth();
  const { selectedCandidate, setSelectedCandidate } = useSelectedCandidate();
  const { selectedJob, setSelectedJob } = useSelectedJob();

  const [activeStep, setActiveStep] = useState<Step>(steps[0]);
  const [error, setError] = useState<string | null>(null);
  const [jobTab, setJobTab] = useState<string>('select');
  const [analysisState, setAnalysisState] = useState<AnalysisState | null>(null);
  const [canAdvance, setCanAdvance] = useState<boolean>(false);
  const scrollRef = useRef<HTMLDivElement>(null);
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));

  const canAccessStep = useCallback((step: Step) => {
    if (!analysisState) {
      return;
    }
    const missing = step.requiredState.find(f => !(analysisState as any)[f])
    return missing;
  }, [analysisState]);

  useEffect(() => {
    if (analysisState !== null) {
      return;
    }

    const analysis = { ...initialState, candidate: selectedCandidate, job: selectedJob }
    setAnalysisState(analysis);
    for (let i = steps.length - 1; i >= 0; i--) {
      const missing = steps[i].requiredState.find(f => !(analysis as any)[f])
      if (!missing) {
        setActiveStep(steps[i]);
        return;
      }
    }
  }, [analysisState, selectedCandidate, selectedJob, setActiveStep, canAccessStep]);

  useEffect(() => {
    if (activeStep.index === steps.length - 1) {
      setCanAdvance(false);
      return;
    }
    const blocked = canAccessStep(steps[activeStep.index + 1]);
    if (blocked) {
      setCanAdvance(false);
    } else {
      setCanAdvance(true);
    }
    if (scrollRef.current) {
      scrollRef.current.scrollTo({
        top: 0,
        behavior: "smooth",
      });
    }
  }, [setCanAdvance, analysisState, activeStep]);

  const handleNext = () => {
    if (activeStep.index === steps.length - 1) {
      return;
    }
    const missing = canAccessStep(steps[activeStep.index + 1]);
    if (missing) {
      setError(`${capitalize(missing)} is necessary before continuing.`);
      return missing;
    }
    
    if (activeStep.index < steps.length - 1) {
      setActiveStep((prevActiveStep) => steps[prevActiveStep.index + 1]);
    }
  };

  const handleBack = () => {
    if (activeStep.index === 0) {
      return;
    }

    setActiveStep((prevActiveStep) => steps[prevActiveStep.index - 1]);
  };

  const moveToStep = (step: number) => {
    const missing = canAccessStep(steps[step]);
    if (missing) {
      setError(`${capitalize(missing)} is needed to access this step.`);
      return;
    }
    setActiveStep(steps[step]);
  }

  const onCandidateSelect = (candidate: Candidate) => {
    if (!analysisState) {
      return;
    }
    analysisState.candidate = candidate;
    setAnalysisState({ ...analysisState });
    setSelectedCandidate(candidate);
    handleNext();
  }

  const onJobSelect = (job: Job) => {
    if (!analysisState) {
      return;
    }
    analysisState.job = job;
    setAnalysisState({ ...analysisState });
    setSelectedJob(job);
    handleNext();
  }

  // Render function for the candidate selection step
  const renderCandidateSelection = () => (
    <CandidatePicker sx={{ pt: 1 }} onSelect={onCandidateSelect} />
  );

  const handleTabChange = (event: React.SyntheticEvent, value: string) => {
    setJobTab(value);
  };

  // Render function for the job description step
  const renderJobDescription = () => {
    return (<Box sx={{ mt: 3 }}>
      <Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
        <Tabs value={jobTab} onChange={handleTabChange} centered>
          <Tab value='select' icon={<WorkOutline />} label="Select Job" />
          <Tab value='create' icon={<WorkAddIcon />} label="Create Job" />
        </Tabs>
      </Box>

      {jobTab === 'select' &&
        <JobPicker onSelect={onJobSelect} />
      }
      {jobTab === 'create' && user &&
        <JobCreator
          onSave={onJobSelect}
        />}
      {jobTab === 'create' && guest &&
        <LoginRestricted><JobCreator
          onSave={onJobSelect}
        /></LoginRestricted>}
    </Box>
    );
  }

  const onAnalysisComplete = (skills: SkillAssessment[]) => {
    if (!analysisState) {
      return;
    }
    analysisState.analysis = skills;
    setAnalysisState({ ...analysisState });
  };

  // Render function for the analysis step
  const renderAnalysis = () => {
    if (!analysisState) {
      return;
    }
    if (!analysisState.job || !analysisState.candidate) {
      return <Box>{JSON.stringify({ job: analysisState.job, candidate: analysisState.candidate })}</Box>
    }
    return (<Box sx={{ mt: 3 }}>
      <JobMatchAnalysis
        variant="small"
        job={analysisState.job}
        candidate={analysisState.candidate}
        onAnalysisComplete={onAnalysisComplete}
      />
    </Box>);
  };

  const renderResume = () => {
    if (!analysisState) {
      return;
    }
    if (!analysisState.job || !analysisState.candidate || !analysisState.analysis) {
      return <></>;
    }

    return (<Box sx={{ mt: 3 }}>
      <ResumeGenerator 
        job={analysisState.job}
        candidate={analysisState.candidate}
        skills={analysisState.analysis}
      />
    </Box>);
  };

  return (
    <Box sx={{
      display: "flex", flexDirection: "column",
      height: "100%", /* Restrict to main-container's height */
      width: "100%",
      minHeight: 0,/* Prevent flex overflow */
      maxHeight: "min-content",
      "& > *:not(.Scrollable)": {
        flexShrink: 0, /* Prevent shrinking */
      },
      position: "relative",
    }}>
      <Paper elevation={4} sx={{ m: 0, borderRadius: 0, mb: 1, p: 0, gap: 1 }}>
        <Stepper activeStep={activeStep.index} alternativeLabel sx={{ mt: 2, mb: 2 }}>
          {steps.map((step, index) => (
            <Step>
              <StepLabel sx={{ cursor: "pointer" }} onClick={() => { moveToStep(index); }}
                slots={{
                  stepIcon: () => (
                    <Avatar key={step.index}
                      sx={{
                        bgcolor: activeStep.index >= step.index ? theme.palette.primary.main : theme.palette.grey[300],
                        color: 'white'
                      }}
                    >
                      {step.icon}
                    </Avatar>
                  )
                }}
              >
                {step.title}
              </StepLabel>
            </Step>
          ))}
        </Stepper>
        <Box sx={{ display: "flex", flexDirection: isMobile ? "column" : "row" }}>
          {analysisState && analysisState.job &&
            <Box sx={{ display: "flex", flexDirection: "row", width: "100%" }}>
              {!isMobile &&
                <Avatar
                  sx={{
                    ml: 1, mt: 1,
                    bgcolor: theme.palette.primary.main,
                    color: 'white'
                  }}
                >
                  <WorkIcon />
                </Avatar>
              }
              <JobInfo variant="minimal" job={analysisState.job} />
            </Box>
          }
          {isMobile && <Box sx={{ display: "flex", borderBottom: "1px solid lightgrey" }} />}
          {!isMobile && <Box sx={{ display: "flex", borderLeft: "1px solid lightgrey" }} />}
          {analysisState && analysisState.candidate &&
            <Box sx={{ display: "flex", flexDirection: "row", width: "100%" }}>
              <CandidateInfo variant="minimal" candidate={analysisState.candidate} sx={{}} />
            </Box>
          }
        </Box>
      </Paper>
      <Scrollable
        ref={scrollRef}
        sx={{
          position: "relative",
          maxHeight: "100%",
          width: "100%",
          display: "flex", flexGrow: 1,
          flex: 1, /* Take remaining space in some-container */
          overflowY: "auto", /* Scroll if content overflows */
        }}>
        {activeStep.label === 'job-selection' && renderJobDescription()}
        {activeStep.label === 'select-candidate' && renderCandidateSelection()}
        {activeStep.label === 'job-analysis' && renderAnalysis()}
        {activeStep.label === 'generated-resume' && renderResume()}
      </Scrollable>

        <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
          <Button
            color="inherit"
          disabled={activeStep.index === steps[0].index}
            onClick={handleBack}
            sx={{ mr: 1 }}
          >
            Back
          </Button>
          <Box sx={{ flex: '1 1 auto' }} />

        {activeStep.index === steps[steps.length - 1].index ? (
          <Button disabled={!canAdvance} onClick={() => { moveToStep(0) }} variant="outlined">
              Start New Analysis
            </Button>
          ) : (
            <Button disabled={!canAdvance} onClick={handleNext} variant="contained">
              {activeStep.index === steps.length - 1 ? 'Done' : 'Next'}
            </Button>
          )}
        </Box>

        {/* Error Snackbar */}
        <Snackbar
          open={!!error}
          autoHideDuration={6000}
          onClose={() => setError(null)}
          anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
        >
          <Alert onClose={() => setError(null)} severity="error" sx={{ width: '100%' }}>
            {error}
          </Alert>
      </Snackbar>
    </Box>);
};

export { JobAnalysisPage };