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

import {
  Autocomplete,
  Box,
  Button,
  Chip,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  List,
  ListItemButton,
  ListItemText,
  Paper,
  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,
} 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 };
}

type JobChoice = { id: number; jobTitle: string; companyName: string };

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

export function buildSuggestedCorrespondenceQueries(
  context: CorrespondenceJobContext,
  subjects: Array<string | null | undefined>,
  labels: { recruiterMailbox: string; companyAndRole: string; companyMail: string; subject: string } = {
    recruiterMailbox: "Recruiter mailbox",
    companyAndRole: "Company + role",
    companyMail: "Company mail",
    subject: "Subject",
  },
) {
  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: labels.recruiterMailbox, value: `(from:${recruiterEmail} OR to:${recruiterEmail}) newer_than:365d` } : null,
    companyName && jobTitle ? { label: labels.companyAndRole, value: `"${companyName}" "${jobTitle}" newer_than:365d` } : null,
    companyName ? { label: labels.companyMail, value: `"${companyName}" (application OR interview OR recruiter) newer_than:365d` } : null,
    ...uniqueSubjects.map((subject) => ({ label: `${labels.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 { language, t } = useI18n();
  const { confirmAction } = useDialogActions();
  const formatConfidence = (value: string) => {
    if (value === "high") return t("correspondenceConfidenceHigh");
    if (value === "medium") return t("correspondenceConfidenceMedium");
    if (value === "low") return t("correspondenceConfidenceLow");
    return t("correspondenceConfidenceUnknown");
  };
  const formatReasonLabel = (label: string) => {
    if (label === "company") return t("company");
    if (label === "recruiterEmail") return t("correspondenceRecruiterEmail");
    if (label === "recruiter") return t("correspondenceRecruiter");
    if (label === "jobTitle") return t("correspondenceJobTitle");
    if (label === "existingSubject") return t("correspondenceExistingSubject");
    if (label === "recency") return t("correspondenceRecent");
    if (label === "status") return t("correspondenceStatus");
    return label;
  };
  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<JobChoice[]>([]);
  const [jobChoiceQuery, setJobChoiceQuery] = useState("");
  const [jobChoicesLoading, setJobChoicesLoading] = useState(false);
  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, t("correspondenceLoadSuggestionsFailed")), "error");
    } finally {
      setGmailMatchesLoading(false);
    }
  }, [jobId, t, toast]);

  const loadAvailableJobs = useCallback(async (query?: string) => {
    try {
      setJobChoicesLoading(true);
      const res = await api.get<JobChoice[]>("/jobapplications/choices", { params: { q: query?.trim() || undefined, limit: 50 } });
      setAvailableJobs((res.data ?? []).filter((item) => item.id !== jobId));
    } catch {
      setAvailableJobs([]);
    } finally {
      setJobChoicesLoading(false);
    }
  }, [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(t(res.data.imported === 1 ? "correspondenceImportedNewMessage" : "correspondenceImportedNewMessages", { count: res.data.imported }), "success");
        } else if (res.data.hasLinkedThreads) {
          toast(t("correspondenceLinkedThreadsCurrent"), "success");
        } else {
          toast(t("correspondenceNoLinkedThreadsForJob"), "success");
        }
      } else if (res.data.imported > 0) {
        toast(t(res.data.imported === 1 ? "correspondenceLinkedImportedMessage" : "correspondenceLinkedImportedMessages", { count: res.data.imported }), "success");
      }

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

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

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

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

  useEffect(() => {
    if (!manageThreadId) return;
    const timer = window.setTimeout(() => void loadAvailableJobs(jobChoiceQuery), jobChoiceQuery.trim() ? 250 : 0);
    return () => window.clearTimeout(timer);
  }, [jobChoiceQuery, loadAvailableJobs, manageThreadId]);

  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), {
    recruiterMailbox: t("correspondenceRecruiterMailbox"),
    companyAndRole: t("correspondenceCompanyAndRole"),
    companyMail: t("correspondenceCompanyMail"),
    subject: t("correspondenceSubject"),
  });

  const send = async () => {
    if (!canSend) return;
    try {
      await api.post("/correspondence", { jobApplicationId: jobId, from, content: text });
      setText("");
      await load();
    } catch (error) {
      toast(getApiErrorMessage(error, t("correspondenceAddFailed")), "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(t("correspondenceAlreadyLinkedToJob"), "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);
    setJobChoiceQuery("");
    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(t(res.data.removedMessages === 1 ? "correspondenceUnlinkedMessage" : "correspondenceUnlinkedMessages", { count: res.data.removedMessages }), "success");
    } catch (error: any) {
      toast(getApiErrorMessage(error, t("correspondenceUnlinkThreadFailed")), "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(t("correspondenceMovedThread", { job: targetJob?.companyName || targetJob?.jobTitle || t("correspondenceJobNumber", { id: res.data.jobApplicationId }) }), "success");
    } catch (error: any) {
      toast(getApiErrorMessage(error, t("correspondenceMoveThreadFailed")), "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={t("correspondenceThread", { id: m.externalThreadId })} variant="outlined" /> : null}
                        {m.externalFrom ? <Chip size="small" label={t("correspondenceFrom", { value: m.externalFrom })} variant="outlined" /> : null}
                        {m.externalTo ? <Chip size="small" label={t("correspondenceTo", { value: m.externalTo })} variant="outlined" /> : null}
                        {m.externalLabelsJson ? <Chip size="small" label={t(JSON.parse(m.externalLabelsJson).length === 1 ? "correspondenceGmailLabel" : "correspondenceGmailLabels", { count: JSON.parse(m.externalLabelsJson).length })} variant="outlined" /> : null}
                        {m.attachmentMetadataJson ? <Chip size="small" label={t(JSON.parse(m.attachmentMetadataJson).length === 1 ? "correspondenceAttachment" : "correspondenceAttachments", { count: JSON.parse(m.attachmentMetadataJson).length })} 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(language === "nb" ? "nb-NO" : "en")}` : ""}
                      </Typography>
                      <IconButton size="small" aria-label={t("correspondenceDeleteTitle")} 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">{t("correspondenceLinkedContinuity")}</Typography>
        <Typography variant="body2" sx={{ color: "text.secondary", mb: 1.25 }}>
          {t("correspondenceLinkedContinuityHelp")}
        </Typography>
        <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
          <Chip size="small" color={gmailStatus?.connected ? "success" : "default"} variant="outlined" label={gmailStatus?.connected ? t("correspondenceGmailConnected") : t("correspondenceGmailNotConnected")} />
          <Chip size="small" color={linkedThreadIds.length > 0 ? "success" : "default"} variant="outlined" label={linkedThreadIds.length > 0 ? t("correspondenceLinkedThreads", { count: linkedThreadIds.length }) : t("correspondenceNoLinkedThreads")} />
          {linkedThreadIds.slice(0, 6).map((threadId) => (
            <Button key={threadId} size="small" variant="text" onClick={() => openManageThread(threadId)}>
              {t("correspondenceManageThread", { id: threadId })}
            </Button>
          ))}
          {gmailStatus?.lastSyncStatus ? (
            <Chip
              size="small"
              color={gmailStatus.lastSyncStatus === "success" ? "success" : "warning"}
              variant="outlined"
              label={gmailStatus.lastSyncStatus === "success"
                ? t("correspondenceLastSyncOk", { mode: gmailStatus.lastSyncMode || t("correspondenceSync") })
                : t("correspondenceLastSyncFailed", { mode: gmailStatus.lastSyncMode || t("correspondenceSync") })}
            />
          ) : null}
          {linkedThreadRefresh ? (
            <Chip
              size="small"
              variant="outlined"
              label={linkedThreadRefresh.imported > 0
                ? t(linkedThreadRefresh.imported === 1 ? "correspondenceLastRefreshImportedMessage" : "correspondenceLastRefreshImportedMessages", { count: linkedThreadRefresh.imported })
                : linkedThreadRefresh.hasLinkedThreads
                  ? t(linkedThreadRefresh.threadsChecked === 1 ? "correspondenceLastRefreshCheckedThread" : "correspondenceLastRefreshCheckedThreads", { count: linkedThreadRefresh.threadsChecked })
                  : t("correspondenceNoRefreshHistory")}
            />
          ) : null}
        </Box>
        {gmailStatus?.lastSyncError ? (
          <Typography variant="body2" sx={{ color: "warning.main", mt: 1 }}>
            {t("correspondenceLatestSyncIssue", { error: 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>{t("correspondenceManageLinkedThread")}</DialogTitle>
        <DialogContent sx={{ display: "flex", flexDirection: "column", gap: 2, pt: 1 }}>
          <Typography variant="body2" sx={{ color: "text.secondary" }}>
            {t("correspondenceManageLinkedThreadHelp")}
          </Typography>
          {manageThreadId ? <Chip label={t("correspondenceThread", { id: manageThreadId })} variant="outlined" sx={{ width: "fit-content" }} /> : null}
          <TextField
            label={t("correspondenceReviewNote")}
            value={manageNote}
            onChange={(event) => setManageNote(event.target.value)}
            multiline
            minRows={2}
            placeholder={t("correspondenceReviewNotePlaceholder")}
          />
          <Autocomplete
            options={availableJobs}
            loading={jobChoicesLoading}
            value={availableJobs.find((item) => item.id === manageTargetJobId) ?? null}
            onInputChange={(_, value, reason) => {
              if (reason === "input" || reason === "clear") setJobChoiceQuery(value);
            }}
            onChange={(_, value) => setManageTargetJobId(value?.id ?? jobId)}
            isOptionEqualToValue={(option, value) => option.id === value.id}
            getOptionLabel={(item) => `${item.companyName || t("correspondenceUnknownCompany")} • ${item.jobTitle}`}
            renderInput={(params) => <TextField {...params} label={t("correspondenceMoveToJob")} placeholder={t("correspondenceSearchEveryJob")} />}
          />
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setManageThreadId(null)} disabled={manageSaving}>{t("close")}</Button>
          <Button color="warning" variant="outlined" onClick={() => void unlinkThread()} disabled={manageSaving || !manageThreadId}>{t("correspondenceUnlinkFromJob")}</Button>
          <Button variant="contained" onClick={() => void relinkThread()} disabled={manageSaving || !manageThreadId || manageTargetJobId === jobId}>{t("correspondenceMoveThread")}</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={t("correspondencePasteEmailPlaceholder")} />
            </>
          ) : (
            <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 }}>
                      {t("correspondenceMatchingAgainst", { company: jobContext.companyName || t("correspondenceThisCompany"), role: jobContext.jobTitle || t("correspondenceThisRole") })}
                    </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 ? t("correspondenceRefreshingLinkedThreads") : t("correspondenceRefreshLinkedThreads")}
                        </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(language === "nb" ? "nb-NO" : "en") })} size="small" /> : null}
                  {gmailStatus.lastSyncAttemptedAt ? <Chip label={t("correspondenceSyncChecked", { date: new Date(gmailStatus.lastSyncAttemptedAt).toLocaleString(language === "nb" ? "nb-NO" : "en") })} size="small" variant="outlined" /> : null}
                  {gmailStatus.lastSyncStatus === "error" && gmailStatus.lastSyncError ? <Chip label={t("correspondenceSyncIssue", { error: 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={t("correspondenceLinkedThreads", { count: linkedThreadIds.length })} />
                      {linkedThreadRefresh ? (
                        <Chip
                          size="small"
                          variant="outlined"
                          label={linkedThreadRefresh.imported > 0
                            ? t(linkedThreadRefresh.imported === 1 ? "correspondenceLastRefreshImportedMessage" : "correspondenceLastRefreshImportedMessages", { count: linkedThreadRefresh.imported })
                            : linkedThreadRefresh.hasLinkedThreads
                              ? t(linkedThreadRefresh.threadsChecked === 1 ? "correspondenceLastRefreshCheckedThread" : "correspondenceLastRefreshCheckedThreads", { count: linkedThreadRefresh.threadsChecked })
                              : t("correspondenceNoLinkedThreadsForJob")}
                        />
                      ) : 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() ? t("correspondenceNoMatchesForOverride") : 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={t("correspondenceConfidenceScore", { confidence: formatConfidence(thread.confidence), score: thread.score })} color={thread.confidence === "high" ? "success" : thread.confidence === "medium" ? "warning" : "default"} />
                                    <Chip size="small" label={t(thread.messageCount === 1 ? "correspondenceMessageCount" : "correspondenceMessagesCount", { count: thread.messageCount })} variant="outlined" />
                                    {thread.hasImportedMessages ? <Chip size="small" label={t("correspondenceAlreadyLinked")} 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(language === "nb" ? "nb-NO" : "en") : ""}</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={t("correspondenceConfidenceScore", { confidence: formatConfidence(message.confidence), score: message.score })} variant="outlined" />
                                          {message.alreadyImported ? <Chip size="small" label={t("correspondenceAlreadyLinked")} 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>
  );
}
