import React, { useMemo } from "react";

import { Box, Chip, Typography, useTheme } from "@mui/material";
import { alpha } from "@mui/material/styles";

import WorkOutlineIcon from "@mui/icons-material/WorkOutline";
import MarkEmailReadIcon from "@mui/icons-material/MarkEmailRead";
import ForumIcon from "@mui/icons-material/Forum";
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
import CloseIcon from "@mui/icons-material/Close";

import { JobApplication } from "../types";

type HistoryEvent = {
  id: number;
  type: string;
  oldValue?: string;
  newValue?: string;
  note?: string;
  at: string;
};

type FlowItem = {
  key: string;
  label: string;
  at: Date;
  color: string;
  icon: React.ReactNode;
};

function normalizeStatus(status?: string): string {
  if (!status) return "Applied";
  if (status === "Interviewing") return "Interview";
  return status;
}

function parseResponseDate(value?: string): Date | null {
  if (!value) return null;
  const parts = value.split(":");
  const raw = parts.length > 1 ? parts.slice(1).join(":") : "";
  const d = new Date(raw);
  return Number.isNaN(+d) ? null : d;
}

function firstStatusChange(history: HistoryEvent[], status: string): Date | null {
  const match = history.find((item) => item.type === "StatusChanged" && normalizeStatus(item.newValue) === status);
  if (!match) return null;
  const d = new Date(match.at);
  return Number.isNaN(+d) ? null : d;
}

function firstResponse(history: HistoryEvent[], job: JobApplication): Date | null {
  if (job.responseDate) {
    const d = new Date(job.responseDate);
    if (!Number.isNaN(+d)) return d;
  }

  const explicit = history.find((item) => item.type === "ReplyReceived");
  if (explicit) {
    const d = new Date(explicit.at);
    if (!Number.isNaN(+d)) return d;
  }

  const updated = history.find((item) => item.type === "ResponseUpdated");
  if (!updated) return null;
  return parseResponseDate(updated.newValue) ?? new Date(updated.at);
}

export default function JobFlowBar({ job, history = [] }: { job: JobApplication | null; history?: HistoryEvent[] }) {
  const theme = useTheme();

  const items = useMemo(() => {
    if (!job) return [] as FlowItem[];

    // Null for a job that has not been applied to yet: there is no Applied milestone to anchor
    // the flow on, so the bar simply starts later.
    const appliedAt = job.dateApplied ? new Date(job.dateApplied) : null;
    const replyAt = firstResponse(history, job);
    const interviewAt = firstStatusChange(history, "Interview") || (normalizeStatus(job.status) === "Interview" ? replyAt ?? appliedAt : null);
    const offerAt = firstStatusChange(history, "Offer") || (normalizeStatus(job.status) === "Offer" ? replyAt ?? interviewAt ?? appliedAt : null);
    const rejectedLabel = normalizeStatus(job.status) === "Ghosted" ? "Ghosted" : "Rejected";
    const rejectedAt = firstStatusChange(history, "Rejected")
      || firstStatusChange(history, "Ghosted")
      || ((normalizeStatus(job.status) === "Rejected" || normalizeStatus(job.status) === "Ghosted") ? replyAt ?? appliedAt : null);

    const next: FlowItem[] = [];

    if (appliedAt) {
      next.push({
        key: "applied",
        label: "Applied",
        at: appliedAt,
        color: theme.palette.info.main,
        icon: <WorkOutlineIcon fontSize="small" />,
      });
    }

    if (replyAt) {
      next.push({
        key: "reply",
        label: "Reply",
        at: replyAt,
        color: theme.palette.success.main,
        icon: <MarkEmailReadIcon fontSize="small" />,
      });
    }

    if (interviewAt) {
      next.push({
        key: "interview",
        label: "Interview",
        at: interviewAt,
        color: theme.palette.primary.main,
        icon: <ForumIcon fontSize="small" />,
      });
    }

    if (offerAt) {
      next.push({
        key: "offer",
        label: "Offer",
        at: offerAt,
        color: theme.palette.success.dark,
        icon: <EmojiEventsIcon fontSize="small" />,
      });
    } else if (rejectedAt) {
      next.push({
        key: normalizeStatus(job.status).toLowerCase(),
        label: rejectedLabel,
        at: rejectedAt,
        color: theme.palette.error.main,
        icon: <CloseIcon fontSize="small" />,
      });
    }

    return next
      .filter((item) => !Number.isNaN(+item.at))
      .sort((a, b) => +a.at - +b.at)
      .filter((item, index, arr) => index === arr.findIndex((other) => other.key === item.key));
  }, [history, job, theme.palette.error.main, theme.palette.info.main, theme.palette.primary.main, theme.palette.success.dark, theme.palette.success.main]);

  if (!job || items.length === 0) return null;

  return (
    <Box sx={{ mb: 2 }}>
      <Typography variant="overline" sx={{ display: "block", mb: 0.75 }}>
        Flow
      </Typography>

      <Box
        sx={{
          display: "flex",
          flexWrap: "wrap",
          gap: 1,
          alignItems: "center",
          p: 1.25,
          borderRadius: 3,
          border: `1px solid ${alpha(theme.palette.text.primary, 0.12)}`,
          background: theme.palette.mode === "dark" ? "rgba(15,23,42,0.42)" : "rgba(248,250,252,0.92)",
        }}
      >
        {items.map((item, index) => (
          <React.Fragment key={`${item.key}-${item.at.toISOString()}`}>
            <Chip
              icon={item.icon as React.ReactElement}
              label={`${item.label} - ${item.at.toLocaleDateString()}`}
              sx={{
                fontWeight: 800,
                color: theme.palette.getContrastText(item.color),
                backgroundColor: item.color,
                borderRadius: 2,
                px: 0.5,
              }}
            />
            {index < items.length - 1 ? (
              <Typography sx={{ color: "text.secondary", fontWeight: 900 }}>
                {"->"}
              </Typography>
            ) : null}
          </React.Fragment>
        ))}
      </Box>
    </Box>
  );
}
