import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";

import {
  Box,
  Button,
  Chip,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  FormControl,
  InputLabel,
  List,
  ListItemButton,
  ListItemText,
  MenuItem,
  Paper,
  Select,
  Tab,
  Tabs,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Typography,
} from "@mui/material";
import { alpha, useTheme } from "@mui/material/styles";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
import MailOutlineIcon from "@mui/icons-material/MailOutline";
import SearchIcon from "@mui/icons-material/Search";
import { IconButton } from "@mui/material";

import { api, getApiErrorMessage } from "../api";
import { useToast } from "../toast";
import {
  CorrespondenceMessage,
  GmailImportMessageResult,
  GmailImportThreadResult,
  GmailJobMatchesResponse,
  GmailRelinkResult,
  GmailStatus,
  GmailThreadRefreshResult,
  GmailUnlinkResult,
  JobApplication,
} from "../types";
import { useDialogActions } from "../dialogs";
import { useI18n } from "../i18n/I18nProvider";

function parseRawEmail(raw: string): { subject?: string; date?: string; from?: string; to?: string; body: string } {
  const lines = raw.replace(/\r\n/g, "\n").split("\n");
  const headers: Record<string, string> = {};
  let i = 0;

  for (; i < lines.length; i++) {
    const line = lines[i];
    if (line.trim() === "") {
      i++;
      break;
    }

    const idx = line.indexOf(":");
    if (idx <= 0) continue;
    const k = line.slice(0, idx).trim().toLowerCase();
    const v = line.slice(idx + 1).trim();
    headers[k] = headers[k] ? `${headers[k]} ${v}` : v;
  }

  const body = lines.slice(i).join("\n").trim();
  const dateRaw = headers["date"];
  let iso: string | undefined;
  if (dateRaw) {
    const d = new Date(dateRaw);
    if (!Number.isNaN(+d)) iso = d.toISOString();
  }

  return { subject: headers["subject"], from: headers["from"], to: headers["to"], date: iso, body };
}

function formatConfidence(value: string) {
  return value ? `${value[0].toUpperCase()}${value.slice(1)} confidence` : "Confidence unknown";
}

function formatReasonLabel(label: string) {
  switch (label) {
    case "company":
      return "Company";
    case "recruiterEmail":
      return "Recruiter email";
    case "recruiter":
      return "Recruiter";
    case "jobTitle":
      return "Job title";
    case "existingSubject":
      return "Existing subject";
    case "recency":
      return "Recent";
    case "status":
      return "Status";
    default:
      return label;
  }
}

interface PagedResult<T> {
  items: T[];
}

export type CorrespondenceJobContext = {
  companyName?: string | null;
  recruiterEmail?: string | null;
  jobTitle?: string | null;
};

export function buildSuggestedCorrespondenceQueries(
  context: CorrespondenceJobContext,
  subjects: Array<string | null | undefined>,
) {
  const uniqueSubjects = Array.from(new Set(subjects.filter(Boolean) as string[])).slice(0, 2);
  const companyName = context.companyName?.trim();
  const recruiterEmail = context.recruiterEmail?.trim();
  const jobTitle = context.jobTitle?.trim();

  return [
    recruiterEmail ? { label: "Recruiter mailbox", value: `(from:${recruiterEmail} OR to:${recruiterEmail}) newer_than:365d` } : null,
    companyName && jobTitle ? { label: "Company + role", value: `"${companyName}" "${jobTitle}" newer_than:365d` } : null,
    companyName ? { label: "Company mail", value: `"${companyName}" (application OR interview OR recruiter) newer_than:365d` } : null,
    ...uniqueSubjects.map((subject) => ({ label: `Subject: ${subject}`, value: `subject:"${subject}" newer_than:365d` })),
  ].filter(Boolean).slice(0, 6) as Array<{ label: string; value: string }>;
}

export default function Correspondence({ jobId, jobContext }: { jobId: number; jobContext: CorrespondenceJobContext }) {
  const theme = useTheme();
  const { toast } = useToast();
  const { t } = useI18n();
  const { confirmAction } = useDialogActions();
  const [messages, setMessages] = useState<CorrespondenceMessage[]>([]);
  const [from, setFrom] = useState<"Me" | "Company">("Me");
  const [text, setText] = useState("");
  const scrollRef = useRef<HTMLDivElement | null>(null);

  const [importOpen, setImportOpen] = useState(false);
  const [importTab, setImportTab] = useState(0);
  const [rawEmail, setRawEmail] = useState("");

  const [gmailStatus, setGmailStatus] = useState<GmailStatus | null>(null);
  const [gmailLoading, setGmailLoading] = useState(false);
  const [gmailQuery, setGmailQuery] = useState("");
  const [gmailMatches, setGmailMatches] = useState<GmailJobMatchesResponse | null>(null);
  const [gmailMatchesLoading, setGmailMatchesLoading] = useState(false);
  const [linkedThreadRefresh, setLinkedThreadRefresh] = useState<GmailThreadRefreshResult | null>(null);
  const [linkedThreadRefreshLoading, setLinkedThreadRefreshLoading] = useState(false);
  const [importingMessageId, setImportingMessageId] = useState<string | null>(null);
  const [importingThreadId, setImportingThreadId] = useState<string | null>(null);
  const [availableJobs, setAvailableJobs] = useState<JobApplication[]>([]);
  const [manageThreadId, setManageThreadId] = useState<string | null>(null);
  const [manageTargetJobId, setManageTargetJobId] = useState<number>(jobId);
  const [manageNote, setManageNote] = useState("");
  const [manageSaving, setManageSaving] = useState(false);
  const autoRefreshKeyRef = useRef<string | null>(null);

  const load = useCallback(async () => {
    const res = await api.get<CorrespondenceMessage[]>(`/correspondence/${jobId}`);
    setMessages(res.data);
  }, [jobId]);

  const loadGmailStatus = useCallback(async () => {
    try {
      setGmailLoading(true);
      const res = await api.get<GmailStatus>("/gmail/status");
      setGmailStatus(res.data);
    } catch {
      setGmailStatus({ connected: false });
    } finally {
      setGmailLoading(false);
    }
  }, []);

  const loadGmailMatches = useCallback(async (queryOverride?: string) => {
    try {
      setGmailMatchesLoading(true);
      const res = await api.get<GmailJobMatchesResponse>("/gmail/job-candidates", {
        params: {
          jobApplicationId: jobId,
          queryOverride: queryOverride?.trim() || undefined,
          maxResultsPerQuery: 6,
        },
      });
      setGmailMatches(res.data);
    } catch (error: any) {
      toast(getApiErrorMessage(error, "Failed to load Gmail suggestions."), "error");
    } finally {
      setGmailMatchesLoading(false);
    }
  }, [jobId, toast]);

  const loadAvailableJobs = useCallback(async () => {
    try {
      const res = await api.get<PagedResult<JobApplication>>("/jobapplications", { params: { page: 1, pageSize: 100, sortBy: "dateApplied", sortDir: "desc" } });
      setAvailableJobs((res.data?.items ?? []).filter((item) => item.id !== jobId));
    } catch {
      setAvailableJobs([]);
    }
  }, [jobId]);

  const linkedThreadIds = useMemo(
    () => Array.from(new Set(messages.map((message) => message.externalThreadId).filter(Boolean) as string[])).sort(),
    [messages],
  );

  const refreshLinkedThreads = useCallback(async (mode: "auto" | "manual" = "manual") => {
    if (!gmailStatus?.connected || linkedThreadIds.length === 0) return null;

    try {
      setLinkedThreadRefreshLoading(true);
      const res = await api.post<GmailThreadRefreshResult>("/gmail/refresh-linked-threads", { jobApplicationId: jobId });
      setLinkedThreadRefresh(res.data);
      await load();
      await loadGmailStatus();
      if (importOpen && importTab === 1) {
        await loadGmailMatches(gmailQuery);
      }

      if (mode === "manual") {
        if (res.data.imported > 0) {
          toast(`Imported ${res.data.imported} new Gmail message${res.data.imported === 1 ? "" : "s"}.`, "success");
        } else if (res.data.hasLinkedThreads) {
          toast("Linked Gmail threads are already current.", "success");
        } else {
          toast("This job does not have any linked Gmail threads yet.", "success");
        }
      } else if (res.data.imported > 0) {
        toast(`Linked Gmail threads imported ${res.data.imported} new message${res.data.imported === 1 ? "" : "s"}.`, "success");
      }

      return res.data;
    } catch (error: any) {
      if (mode === "manual") {
        toast(getApiErrorMessage(error, "Failed to refresh linked Gmail threads."), "error");
      }
      return null;
    } finally {
      setLinkedThreadRefreshLoading(false);
    }
  }, [gmailQuery, gmailStatus?.connected, importOpen, importTab, jobId, linkedThreadIds.length, load, loadGmailMatches, loadGmailStatus, toast]);

  useEffect(() => {
    void load();
  }, [load]);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    el.scrollTop = el.scrollHeight;
  }, [messages.length]);

  useEffect(() => {
    void loadGmailStatus();
    void loadAvailableJobs();
  }, [loadAvailableJobs, loadGmailStatus]);

  useEffect(() => {
    if (!gmailStatus?.connected || linkedThreadIds.length === 0) {
      autoRefreshKeyRef.current = null;
      return;
    }

    const refreshKey = `${jobId}:${linkedThreadIds.join("|")}`;
    if (autoRefreshKeyRef.current === refreshKey) return;
    autoRefreshKeyRef.current = refreshKey;
    void refreshLinkedThreads("auto");
  }, [gmailStatus?.connected, jobId, linkedThreadIds, refreshLinkedThreads]);

  useEffect(() => {
    if (!importOpen || importTab !== 1 || !gmailStatus?.connected) return;
    void loadGmailMatches(gmailQuery);
  }, [importOpen, importTab, gmailStatus?.connected, gmailQuery, loadGmailMatches]);

  useEffect(() => {
    const onMessage = (event: MessageEvent) => {
      const data = event.data as { source?: string; status?: string; message?: string };
      if (data?.source !== "jobtracker-gmail-oauth") return;
      if (data.status === "connected") {
        toast(data.message || t("googleLinkedSuccess"), "success");
        void loadGmailStatus();
        setImportTab(1);
        void loadGmailMatches(gmailQuery);
      } else {
        toast(data.message || t("googleAuthFailed"), "error");
      }
    };

    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, [gmailQuery, loadGmailMatches, loadGmailStatus, t, toast]);

  const canSend = useMemo(() => text.trim().length > 0, [text]);

  const suggestedQueries = buildSuggestedCorrespondenceQueries(jobContext, messages.map((message) => message.subject));

  const send = async () => {
    if (!canSend) return;
    try {
      await api.post("/correspondence", { jobApplicationId: jobId, from, content: text });
      setText("");
      await load();
    } catch (error) {
      toast(getApiErrorMessage(error, "Failed to add message."), "error");
    }
  };

  const importEmail = async () => {
    const parsed = parseRawEmail(rawEmail);
    if (!parsed.body && !parsed.subject && !rawEmail.trim()) {
      toast(t("addJobModalPasteUrlFirst"), "error");
      return;
    }

    try {
      await api.post("/correspondence", {
        jobApplicationId: jobId,
        from,
        channel: "Email",
        subject: parsed.subject ?? null,
        content: parsed.body || rawEmail,
        date: parsed.date ?? null,
        externalFrom: parsed.from ?? null,
        externalTo: parsed.to ?? null,
      });
      setImportOpen(false);
      setRawEmail("");
      await load();
      toast(t("correspondenceLogEmail"), "success");
    } catch (error) {
      toast(getApiErrorMessage(error, t("addJobModalImportFailed")), "error");
    }
  };

  const connectGmail = async () => {
    try {
      const res = await api.get<{ url: string }>("/gmail/connect-url");
      const popup = window.open(res.data.url, "jobtracker-gmail-connect", "width=620,height=760,resizable=yes,scrollbars=yes");
      if (!popup) toast(t("correspondenceBlockedPopup"), "error");
    } catch (error) {
      toast(getApiErrorMessage(error, t("correspondenceStartGmailFailed")), "error");
    }
  };

  const disconnectGmail = async () => {
    try {
      await api.delete("/gmail/connection");
      setGmailStatus({ connected: false });
      setGmailMatches(null);
      setLinkedThreadRefresh(null);
      toast(t("googleUnlinked"), "success");
    } catch (error) {
      toast(getApiErrorMessage(error, t("correspondenceDisconnectFailed")), "error");
    }
  };

  const deleteMessage = async (messageId: number) => {
    if (!(await confirmAction(t("correspondenceDeleteConfirm"), { title: t("correspondenceDeleteTitle"), confirmLabel: t("adminUsersDelete"), destructive: true }))) return;
    try {
      await api.delete(`/correspondence/${messageId}`);
      await load();
      toast(t("correspondenceDeleted"), "success");
    } catch (error) {
      toast(getApiErrorMessage(error, t("correspondenceDeleteFailed")), "error");
    }
  };

  const importGmailMessage = async (messageId: string) => {
    try {
      setImportingMessageId(messageId);
      const res = await api.post<GmailImportMessageResult>("/gmail/import", { jobApplicationId: jobId, messageId });
      await load();
      await loadGmailMatches(gmailQuery);
      if (res.data.imported > 0) {
        toast(t("correspondenceImportEmail"), "success");
      } else {
        toast("This Gmail message is already linked to the job.", "success");
      }
    } catch (error: any) {
      toast(getApiErrorMessage(error, t("correspondenceImportGmailFailed")), "error");
    } finally {
      setImportingMessageId(null);
    }
  };

  const importGmailThread = async (threadId: string, messageIds: string[]) => {
    try {
      setImportingThreadId(threadId);
      const res = await api.post<GmailImportThreadResult>("/gmail/import-thread", { jobApplicationId: jobId, threadId, messageIds });
      await load();
      await loadGmailMatches(gmailQuery);
      toast(t("correspondenceImportThreadResult", { imported: res.data.imported, skippedText: res.data.skipped ? t("correspondenceImportThreadSkipped", { count: res.data.skipped }) : "" }), "success");
    } catch (error: any) {
      toast(getApiErrorMessage(error, t("correspondenceImportThreadFailed")), "error");
    } finally {
      setImportingThreadId(null);
    }
  };

  const openManageThread = (threadId: string) => {
    setManageThreadId(threadId);
    setManageTargetJobId(jobId);
    setManageNote("");
  };

  const unlinkThread = async () => {
    if (!manageThreadId) return;
    setManageSaving(true);
    try {
      const res = await api.post<GmailUnlinkResult>("/gmail/unlink-thread", {
        jobApplicationId: jobId,
        threadId: manageThreadId,
        note: manageNote.trim() || null,
        nextDecision: "review",
      });
      await load();
      await loadGmailMatches(gmailQuery);
      setManageThreadId(null);
      toast(`Unlinked ${res.data.removedMessages} message${res.data.removedMessages === 1 ? "" : "s"} from this job.`, "success");
    } catch (error: any) {
      toast(getApiErrorMessage(error, "Failed to unlink the Gmail thread."), "error");
    } finally {
      setManageSaving(false);
    }
  };

  const relinkThread = async () => {
    if (!manageThreadId || manageTargetJobId <= 0 || manageTargetJobId === jobId) return;
    setManageSaving(true);
    try {
      const res = await api.post<GmailRelinkResult>("/gmail/relink-thread", {
        jobApplicationId: manageTargetJobId,
        threadId: manageThreadId,
        removeFromOtherJobs: true,
        note: manageNote.trim() || null,
      });
      await load();
      await loadGmailMatches(gmailQuery);
      setManageThreadId(null);
      const targetJob = availableJobs.find((item) => item.id === manageTargetJobId);
      toast(`Moved thread to ${targetJob?.company?.name || targetJob?.jobTitle || `job ${res.data.jobApplicationId}`}.`, "success");
    } catch (error: any) {
      toast(getApiErrorMessage(error, "Failed to move the Gmail thread."), "error");
    } finally {
      setManageSaving(false);
    }
  };

  return (
    <Box>
      <Paper ref={scrollRef} sx={{ p: 1.5, maxHeight: 360, overflowY: "auto", background: theme.palette.mode === "dark" ? "rgba(15,23,42,0.45)" : "rgba(255,255,255,0.75)", backdropFilter: "blur(8px)" }}>
        {messages.length === 0 ? (
          <Typography sx={{ color: "text.secondary", py: 2, textAlign: "center" }}>{t("correspondenceNoMessages")}</Typography>
        ) : (
          <Box sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
            {messages.map((m) => {
              const isMe = (m.from || "").toLowerCase() === "me";
              const accent = isMe ? theme.palette.primary.main : theme.palette.warning.main;
              return (
                <Box key={m.id} sx={{ display: "flex", justifyContent: isMe ? "flex-end" : "flex-start" }}>
                  <Box sx={{ maxWidth: "80%", borderRadius: 3, p: 1.25, border: `1px solid ${alpha(accent, theme.palette.mode === "dark" ? 0.32 : 0.22)}`, background: alpha(accent, theme.palette.mode === "dark" ? 0.14 : 0.1), color: "text.primary" }}>
                    {m.subject ? <Typography sx={{ fontWeight: 800, mb: 0.5 }}>{m.subject}</Typography> : null}
                    <Typography sx={{ whiteSpace: "pre-wrap", lineHeight: 1.35 }}>{m.content}</Typography>
                    {(m.externalThreadId || m.externalFrom || m.externalTo || m.externalLabelsJson || m.attachmentMetadataJson) ? (
                      <Box sx={{ display: "flex", gap: 0.75, flexWrap: "wrap", mt: 1 }}>
                        {m.externalThreadId ? <Chip size="small" label={`Thread ${m.externalThreadId}`} variant="outlined" /> : null}
                        {m.externalFrom ? <Chip size="small" label={`From ${m.externalFrom}`} variant="outlined" /> : null}
                        {m.externalTo ? <Chip size="small" label={`To ${m.externalTo}`} variant="outlined" /> : null}
                        {m.externalLabelsJson ? <Chip size="small" label={`${JSON.parse(m.externalLabelsJson).length} Gmail label${JSON.parse(m.externalLabelsJson).length === 1 ? "" : "s"}`} variant="outlined" /> : null}
                        {m.attachmentMetadataJson ? <Chip size="small" label={`${JSON.parse(m.attachmentMetadataJson).length} attachment${JSON.parse(m.attachmentMetadataJson).length === 1 ? "" : "s"}`} variant="outlined" /> : null}
                      </Box>
                    ) : null}
                    <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, alignItems: "flex-end", mt: 0.75 }}>
                      <Typography variant="caption" sx={{ color: "text.secondary" }}>
                        {isMe ? t("correspondenceMe") : t("correspondenceCompany")}{m.channel ? ` - ${m.channel}` : ""}{m.date ? ` - ${new Date(m.date).toLocaleString()}` : ""}
                      </Typography>
                      <IconButton size="small" onClick={() => void deleteMessage(m.id)} sx={{ color: "text.secondary" }}>
                        <DeleteOutlineIcon fontSize="small" />
                      </IconButton>
                    </Box>
                  </Box>
                </Box>
              );
            })}
          </Box>
        )}
      </Paper>

      <Box sx={{ mt: 1.5, p: 1.5, borderRadius: 3, border: "none", boxShadow: "0px 1px 2px 0px rgba(15,23,42,0.04), 0px 8px 24px -12px rgba(15,23,42,0.12)", backgroundColor: "background.default" }}>
        <Typography variant="overline">Linked Gmail thread continuity</Typography>
        <Typography variant="body2" sx={{ color: "text.secondary", mb: 1.25 }}>
          Linked Gmail refresh only checks threads that are already tied to this job, so new correspondence can appear here without re-importing the whole thread.
        </Typography>
        <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
          <Chip size="small" color={gmailStatus?.connected ? "success" : "default"} variant="outlined" label={gmailStatus?.connected ? "Gmail connected" : "Gmail not connected"} />
          <Chip size="small" color={linkedThreadIds.length > 0 ? "success" : "default"} variant="outlined" label={linkedThreadIds.length > 0 ? `Linked threads: ${linkedThreadIds.length}` : "No linked threads yet"} />
          {linkedThreadIds.slice(0, 6).map((threadId) => (
            <Button key={threadId} size="small" variant="text" onClick={() => openManageThread(threadId)}>
              Manage {threadId}
            </Button>
          ))}
          {gmailStatus?.lastSyncStatus ? (
            <Chip
              size="small"
              color={gmailStatus.lastSyncStatus === "success" ? "success" : "warning"}
              variant="outlined"
              label={gmailStatus.lastSyncStatus === "success"
                ? `Last Gmail sync ${gmailStatus.lastSyncMode || "sync"} ok`
                : `Last Gmail sync ${gmailStatus.lastSyncMode || "sync"} failed`}
            />
          ) : null}
          {linkedThreadRefresh ? (
            <Chip
              size="small"
              variant="outlined"
              label={linkedThreadRefresh.imported > 0
                ? `Last linked refresh imported ${linkedThreadRefresh.imported} new message${linkedThreadRefresh.imported === 1 ? "" : "s"}`
                : linkedThreadRefresh.hasLinkedThreads
                  ? `Last linked refresh checked ${linkedThreadRefresh.threadsChecked} linked thread${linkedThreadRefresh.threadsChecked === 1 ? "" : "s"}`
                  : "No linked Gmail refresh history yet"}
            />
          ) : null}
        </Box>
        {gmailStatus?.lastSyncError ? (
          <Typography variant="body2" sx={{ color: "warning.main", mt: 1 }}>
            Latest Gmail sync issue: {gmailStatus.lastSyncError}
          </Typography>
        ) : null}
      </Box>

      <Box sx={{ display: "flex", gap: 1, alignItems: "flex-start", mt: 1.5, flexWrap: "wrap" }}>
        <ToggleButtonGroup exclusive value={from} onChange={(_, v) => v && setFrom(v)} size="small">
          <ToggleButton value="Me">{t("correspondenceMe")}</ToggleButton>
          <ToggleButton value="Company">{t("correspondenceCompany")}</ToggleButton>
        </ToggleButtonGroup>

        <Button variant="outlined" size="small" onClick={() => setImportOpen(true)}>{t("correspondenceImportEmail")}</Button>

        <TextField label={t("correspondenceLogNoteOrMessage")} value={text} onChange={(e) => setText(e.target.value)} multiline minRows={3} sx={{ flex: "1 1 320px" }} helperText={t("correspondenceCharacters", { count: text.length })} />

        <Button variant="contained" onClick={send} disabled={!canSend}>{t("correspondenceAdd")}</Button>
      </Box>

      <Dialog open={Boolean(manageThreadId)} onClose={() => setManageThreadId(null)} fullWidth maxWidth="sm">
        <DialogTitle>Manage linked Gmail thread</DialogTitle>
        <DialogContent sx={{ display: "flex", flexDirection: "column", gap: 2, pt: 1 }}>
          <Typography variant="body2" sx={{ color: "text.secondary" }}>
            Unlink this thread from the current job, or move it to another existing job.
          </Typography>
          {manageThreadId ? <Chip label={`Thread ${manageThreadId}`} variant="outlined" sx={{ width: "fit-content" }} /> : null}
          <TextField
            label="Review note"
            value={manageNote}
            onChange={(event) => setManageNote(event.target.value)}
            multiline
            minRows={2}
            placeholder="Why this thread should stay in review or move to another job."
          />
          <FormControl fullWidth>
            <InputLabel>Move to job</InputLabel>
            <Select
              value={String(manageTargetJobId)}
              label="Move to job"
              onChange={(event) => setManageTargetJobId(Number(event.target.value))}
            >
              <MenuItem value={String(jobId)}>Keep on current job</MenuItem>
              {availableJobs.map((item) => (
                <MenuItem key={item.id} value={String(item.id)}>
                  {item.company?.name || "Unknown company"} • {item.jobTitle}
                </MenuItem>
              ))}
            </Select>
          </FormControl>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setManageThreadId(null)} disabled={manageSaving}>Close</Button>
          <Button color="warning" variant="outlined" onClick={() => void unlinkThread()} disabled={manageSaving || !manageThreadId}>Unlink from this job</Button>
          <Button variant="contained" onClick={() => void relinkThread()} disabled={manageSaving || !manageThreadId || manageTargetJobId === jobId}>Move thread</Button>
        </DialogActions>
      </Dialog>

      <Dialog open={importOpen} onClose={() => setImportOpen(false)} fullWidth maxWidth="md">
        <DialogTitle>{t("correspondenceImportTitle")}</DialogTitle>
        <DialogContent>
          <Tabs value={importTab} onChange={(_, v) => setImportTab(v)} sx={{ mb: 2 }}>
            <Tab label={t("correspondencePasteEmail")} />
            <Tab label={t("google")} />
          </Tabs>

          {importTab === 0 ? (
            <>
              <Typography sx={{ color: "text.secondary", mb: 1 }}>{t("correspondencePasteEmailHelp")}</Typography>
              <TextField multiline minRows={10} fullWidth value={rawEmail} onChange={(e) => setRawEmail(e.target.value)} placeholder={"Subject: ...\nDate: ...\nFrom: ...\nTo: ...\n\nBody..."} />
            </>
          ) : (
            <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
              <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap", alignItems: "center" }}>
                <Box>
                  <Typography sx={{ fontWeight: 800 }}>{t("correspondenceGoogleGmail")}</Typography>
                  <Typography variant="body2" sx={{ color: "text.secondary" }}>
                    {gmailLoading ? t("correspondenceCheckingConnection") : gmailStatus?.connected ? t("correspondenceConnectedAs", { email: gmailStatus.gmailAddress || "" }) : t("correspondenceConnectGmailHint")}
                  </Typography>
                  {jobContext.companyName || jobContext.jobTitle ? (
                    <Typography variant="body2" sx={{ color: "text.secondary", mt: 0.5 }}>
                      Matching against {jobContext.companyName || "this company"} / {jobContext.jobTitle || "this role"}
                    </Typography>
                  ) : null}
                </Box>
                <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
                  {gmailStatus?.connected ? (
                    <>
                      {linkedThreadIds.length > 0 ? (
                        <Button variant="outlined" onClick={() => void refreshLinkedThreads("manual")} disabled={linkedThreadRefreshLoading}>
                          {linkedThreadRefreshLoading ? "Refreshing linked threads..." : "Refresh linked threads"}
                        </Button>
                      ) : null}
                      <Button variant="outlined" onClick={() => void loadGmailMatches(gmailQuery)} disabled={gmailMatchesLoading}>{t("correspondenceRefresh")}</Button>
                      <Button variant="outlined" color="error" onClick={() => void disconnectGmail()}>{t("correspondenceDisconnect")}</Button>
                    </>
                  ) : (
                    <Button variant="contained" onClick={() => void connectGmail()}>{t("correspondenceConnectGmail")}</Button>
                  )}
                </Box>
              </Box>

              {gmailStatus?.connected ? (
                <>
                  <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
                    {suggestedQueries.map((item) => (
                      <Chip key={item.label} icon={<AutoAwesomeIcon />} label={item.label} clickable variant="outlined" onClick={() => setGmailQuery(item.value)} />
                    ))}
                  </Box>
                  <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", alignItems: "center" }}>
                    <TextField label={t("correspondenceSearchGmail")} value={gmailQuery} onChange={(e) => setGmailQuery(e.target.value)} placeholder={t("correspondenceSearchGmailPlaceholder")} size="small" fullWidth />
                    <Button variant="outlined" startIcon={<SearchIcon />} onClick={() => void loadGmailMatches(gmailQuery)} disabled={gmailMatchesLoading}>{t("correspondenceSearch")}</Button>
                  </Box>
                  {gmailMatches?.queries?.length ? (
                    <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
                      {gmailMatches.queries.slice(0, 4).map((query) => (
                        <Chip key={query} size="small" label={query} variant="outlined" />
                      ))}
                    </Box>
                  ) : null}
                  {gmailStatus.lastSyncedAt ? <Chip label={t("correspondenceLastSynced", { date: new Date(gmailStatus.lastSyncedAt).toLocaleString() })} size="small" /> : null}
                  {gmailStatus.lastSyncAttemptedAt ? <Chip label={`Sync checked ${new Date(gmailStatus.lastSyncAttemptedAt).toLocaleString()}`} size="small" variant="outlined" /> : null}
                  {gmailStatus.lastSyncStatus === "error" && gmailStatus.lastSyncError ? <Chip label={`Sync issue: ${gmailStatus.lastSyncError}`} size="small" color="warning" variant="outlined" /> : null}
                  {linkedThreadIds.length > 0 ? (
                    <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
                      <Chip size="small" color="success" variant="outlined" label={`Linked threads: ${linkedThreadIds.length}`} />
                      {linkedThreadRefresh ? (
                        <Chip
                          size="small"
                          variant="outlined"
                          label={linkedThreadRefresh.imported > 0
                            ? `Last refresh imported ${linkedThreadRefresh.imported} new message${linkedThreadRefresh.imported === 1 ? "" : "s"}`
                            : linkedThreadRefresh.hasLinkedThreads
                              ? `Last refresh checked ${linkedThreadRefresh.threadsChecked} linked thread${linkedThreadRefresh.threadsChecked === 1 ? "" : "s"}`
                              : "No linked Gmail threads yet"}
                        />
                      ) : null}
                    </Box>
                  ) : null}
                  <Paper variant="outlined" sx={{ maxHeight: 420, overflowY: "auto" }}>
                    {gmailMatchesLoading ? (
                      <Box sx={{ py: 5, display: "flex", justifyContent: "center" }}><CircularProgress size={28} /></Box>
                    ) : !gmailMatches || gmailMatches.threads.length === 0 ? (
                      <Typography sx={{ color: "text.secondary", p: 2 }}>
                        {gmailQuery.trim() ? "No Gmail matches for this job and search override yet." : t("correspondenceNoGmailMessages")}
                      </Typography>
                    ) : (
                      <List disablePadding>
                        {gmailMatches.threads.map((thread, threadIndex) => (
                          <React.Fragment key={thread.threadId}>
                            {threadIndex > 0 ? <Divider /> : null}
                            <Box sx={{ p: 1.5, backgroundColor: alpha(theme.palette.primary.main, 0.04) }}>
                              <Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, flexWrap: "wrap", alignItems: "center", mb: 1 }}>
                                <Box>
                                  <Typography sx={{ fontWeight: 800 }}>{thread.subject || t("correspondenceNoSubject")}</Typography>
                                  <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", mt: 0.75 }}>
                                    <Chip size="small" label={`${formatConfidence(thread.confidence)} · score ${thread.score}`} color={thread.confidence === "high" ? "success" : thread.confidence === "medium" ? "warning" : "default"} />
                                    <Chip size="small" label={`${thread.messageCount} message${thread.messageCount === 1 ? "" : "s"}`} variant="outlined" />
                                    {thread.hasImportedMessages ? <Chip size="small" label="Already linked" variant="outlined" color="success" /> : null}
                                  </Box>
                                  <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", mt: 1 }}>
                                    {thread.matchReasons.map((reason) => (
                                      <Chip key={`${thread.threadId}-${reason.label}-${reason.value}`} size="small" label={`${formatReasonLabel(reason.label)}: ${reason.value}`} variant="outlined" />
                                    ))}
                                  </Box>
                                </Box>
                                <Button startIcon={<MailOutlineIcon />} variant="outlined" size="small" disabled={importingThreadId === thread.threadId} onClick={() => void importGmailThread(thread.threadId, thread.messages.map((x) => x.id))}>
                                  {importingThreadId === thread.threadId ? t("correspondenceImporting") : t("correspondenceImportThread")}
                                </Button>
                              </Box>
                              {thread.messages.map((message, index) => (
                                <React.Fragment key={message.id}>
                                  {index > 0 ? <Divider sx={{ my: 1 }} /> : null}
                                  <ListItemButton sx={{ alignItems: "flex-start", px: 0, py: 1 }}>
                                    <ListItemText
                                      secondaryTypographyProps={{ component: "div" }}
                                      primary={<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}><Typography sx={{ fontWeight: 700 }}>{message.subject || t("correspondenceNoSubject")}</Typography><Typography variant="caption" sx={{ color: "text.secondary" }}>{message.date ? new Date(message.date).toLocaleString() : ""}</Typography></Box>}
                                      secondary={<Box component="span" sx={{ mt: 0.5, display: "block" }}>
                                        <Typography component="span" variant="body2" sx={{ color: "text.primary", display: "block" }}>{t("correspondenceFromLabel", { value: message.from || t("correspondenceUnknown") })}</Typography>
                                        <Typography component="span" variant="body2" sx={{ color: "text.secondary", mt: 0.25, display: "block" }}>{message.snippet}</Typography>
                                        <Box component="span" sx={{ display: "flex", gap: 1, flexWrap: "wrap", mt: 1 }}>
                                          <Chip size="small" label={`${formatConfidence(message.confidence)} · score ${message.score}`} variant="outlined" />
                                          {message.alreadyImported ? <Chip size="small" label="Already linked" color="success" variant="outlined" /> : null}
                                          {message.matchReasons.map((reason) => (
                                            <Chip key={`${message.id}-${reason.label}-${reason.value}`} size="small" label={`${formatReasonLabel(reason.label)}: ${reason.value}`} variant="outlined" />
                                          ))}
                                        </Box>
                                      </Box>}
                                    />
                                    <Button variant="contained" size="small" disabled={importingMessageId === message.id} onClick={() => void importGmailMessage(message.id)}>
                                      {importingMessageId === message.id ? t("correspondenceImporting") : t("correspondenceImportEmail")}
                                    </Button>
                                  </ListItemButton>
                                </React.Fragment>
                              ))}
                            </Box>
                          </React.Fragment>
                        ))}
                      </List>
                    )}
                  </Paper>
                </>
              ) : null}
            </Box>
          )}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setImportOpen(false)}>{t("correspondenceClose")}</Button>
          {importTab === 0 ? <Button variant="contained" onClick={importEmail}>{t("correspondenceLogEmail")}</Button> : null}
        </DialogActions>
      </Dialog>
    </Box>
  );
}
