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

import { Accordion, AccordionDetails, AccordionSummary, Alert, Avatar, Box, Button, Checkbox, Chip, FormControl, FormControlLabel, InputLabel, LinearProgress, MenuItem, Paper, Select, Tab, Tabs, TextField, Typography } from "@mui/material";

import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import PhotoCameraOutlinedIcon from "@mui/icons-material/PhotoCameraOutlined";

import { api, getApiErrorMessage } from "../api";
import CropImageDialog from "../components/CropImageDialog";
import ProfileCompleteness from "./career/ProfileCompleteness";
import CareerWorkspaceOverview from "./career/CareerWorkspaceOverview";
import {
  EducationSection,
  InterestsSection,
  LanguagesSection,
  LongTailSections,
  OtherSectionsSection,
  PersonalInformationSection,
  ProfessionalSummarySection,
  SkillsSection,
  WorkExperienceSection,
} from "./career/CareerProfileSections";
import { useToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";
import { useAccountPlan } from "../accountPlan";
import ProFeatureNotice from "../components/ProFeatureNotice";
import type { UserOperation } from "../types";
import {
  emptyStructuredCv,
  getStructuredCvFieldMetadata,
  normalizeStructuredCv,
  StructuredCvProfile,
} from "../profileCv";


type ExtractionRun = {
  id: number;
  trigger: string;
  status: string;
  artifactFileName?: string;
  startedAtUtc: string;
  completedAtUtc?: string;
  appliedAtUtc?: string;
  parserVersion: string;
  normalizerVersion: string;
  llmPromptVersion: string;
  errorMessage?: string;
  operation?: UserOperation | null;
};

type CvImportDiff = {
  totalAdded: number;
  totalUpdated: number;
  totalLowConfidence: number;
  hasChanges: boolean;
  categories: Array<{
    category: string;
    added: Array<{ id: string; label: string; confidence: string }>;
    updated: Array<{ id: string; label: string; confidence: string }>;
    unchangedCount: number;
    lowConfidenceCount: number;
  }>;
};

type CvRunDiffResponse = { runId: number; status: string; diff: CvImportDiff };

type QueuedCvRunResponse = {
  queued: boolean;
  extractionRunId: number;
  status: string;
  operation?: UserOperation | null;
  statusUrl?: string | null;
  created: boolean;
};

const activeOperationStatuses = new Set(["queued", "running", "waiting_for_retry", "waiting_for_external_fallback"]);
const activeRunLabels = new Set(["queued", "running", "processing locally", "waiting to retry", "waiting for approved fallback"]);

function cvRunStatus(run: ExtractionRun) {
  const operation = run.operation;
  if (!operation || operation.status === "succeeded") return run.status;
  if (operation.cancellationRequestedAtUtc) return "cancellation requested";
  switch (operation.status) {
    case "running": return "processing locally";
    case "waiting_for_retry": return "waiting to retry";
    case "waiting_for_external_fallback": return "waiting for approved fallback";
    default: return operation.status;
  }
}

type MeResponse = {
  provider?: "local" | "google" | "external";
  id?: string;
  email?: string;
  userName?: string;
  firstName?: string;
  lastName?: string;
  displayName?: string;
  profileCvText?: string;
  profileCvStructureJson?: string;
  avatarImageDataUrl?: string;
  roles?: string[];
  googleLink?: {
    linked: boolean;
    email?: string | null;
    linkedAt?: string | null;
  } | null;
};

const CV_UPLOAD_ACCEPT = ".pdf,.docx,.txt,.md,image/png,image/jpeg,image/webp,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain,text/markdown";
const AVATAR_UPLOAD_ACCEPT = "image/png,image/jpeg,image/webp";
function initialsFrom(values: Array<string | undefined>) {
  const joined = values.map((x) => (x ?? "").trim()).filter(Boolean);
  if (joined.length === 0) return "?";
  if (joined.length === 1) {
    const parts = joined[0].split(/[\s@._-]+/).filter(Boolean);
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0][0] + parts[1][0]).toUpperCase();
  }
  return (joined[0][0] + joined[1][0]).toUpperCase();
}



// Phase 3: the master profile now comes from the relational source of truth via /career/profile.
type CareerSectionStatus = { key: string; label: string; complete: boolean; count: number };
type CareerCompleteness = { percent: number; missing: string[]; sections: CareerSectionStatus[] };
type CareerProfileResponse = { profile: StructuredCvProfile; completeness: CareerCompleteness; cvText?: string | null };
type CareerVersion = { version: number; source: string; createdAtUtc: string; isCurrent: boolean };
type CareerWorkspaceSection = "overview" | "profile" | "import";

function initialWorkspaceSection(): CareerWorkspaceSection {
  if (typeof window === "undefined") return "overview";
  const section = new URLSearchParams(window.location.search).get("section");
  return section === "profile" || section === "import" ? section : "overview";
}

// CareerProfilePage backs /career: the master career profile — the single editable source of
// truth for all future generated documents. Split out from ProfilePage in Phase 2.2; wired to the
// relational /career/profile API in Phase 3.
export default function CareerProfilePage() {
  const { canUseAi } = useAccountPlan();
  // Retained so the shared JSX (copied from ProfilePage) reads identically; hardcoded for /career.
  const careerOnly = true;
  const { toast } = useToast();
  const { language, t } = useI18n();
  const cvInputRef = useRef<HTMLInputElement | null>(null);
  const avatarInputRef = useRef<HTMLInputElement | null>(null);
  const [me, setMe] = useState<MeResponse | null>(null);
  const [loading, setLoading] = useState(false);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [uploadingCv, setUploadingCv] = useState(false);
  const [improvingCv, setImprovingCv] = useState(false);
  const [rebuildingCv, setRebuildingCv] = useState(false);
  const [uploadingAvatar, setUploadingAvatar] = useState(false);
  const [avatarFile, setAvatarFile] = useState<File | null>(null);
  const [cropOpen, setCropOpen] = useState(false);

  const [headline, setHeadline] = useState("");
  const [profileCvText, setProfileCvText] = useState("");
  const [parsingCvSections, setParsingCvSections] = useState(false);
  const [reprocessingCv, setReprocessingCv] = useState(false);
  const [structuredCv, setStructuredCv] = useState<StructuredCvProfile>(emptyStructuredCv());
  const [profileDirty, setProfileDirty] = useState(false);
  const [completeness, setCompleteness] = useState<CareerCompleteness | null>(null);
  const [versions, setVersions] = useState<CareerVersion[]>([]);
  // The raw import/section parser remains available as an advanced recovery tool.
  const [showAdvancedCvTools, setShowAdvancedCvTools] = useState(false);
  const [workspaceSection, setWorkspaceSection] = useState<CareerWorkspaceSection>(initialWorkspaceSection);

  const navigateWorkspace = useCallback((next: CareerWorkspaceSection) => {
    setWorkspaceSection(next);
    if (typeof window === "undefined") return;
    const url = new URL(window.location.href);
    if (next === "overview") url.searchParams.delete("section");
    else url.searchParams.set("section", next);
    window.history.replaceState(window.history.state, "", `${url.pathname}${url.search}${url.hash}`);
  }, []);

  const loadVersions = useCallback(async () => {
    try {
      const r = await api.get<CareerVersion[]>("/career/profile/versions");
      setVersions(r.data ?? []);
    } catch {
      setVersions([]);
    }
  }, []);

  const restoreVersion = useCallback(async (version: number) => {
    setLoading(true);
    try {
      const r = await api.post<CareerProfileResponse>(`/career/profile/versions/${version}/restore`);
      setStructuredCv(normalizeStructuredCv(r.data?.profile ?? emptyStructuredCv()));
      setCompleteness(r.data?.completeness ?? null);
      setProfileDirty(false);
      await loadVersions();
      toast(t("profileUpdated"), "success");
    } catch (e: any) {
      toast(String(e?.response?.data || e?.message || t("profileUpdateFailed")), "error");
    } finally {
      setLoading(false);
    }
  }, [loadVersions, t, toast]);
  const [extractionRuns, setExtractionRuns] = useState<ExtractionRun[]>([]);
  const [runDiffs, setRunDiffs] = useState<Record<number, CvImportDiff>>({});
  const [reviewingRunId, setReviewingRunId] = useState<number | null>(null);
  const [acceptedLowConfidenceIds, setAcceptedLowConfidenceIds] = useState<Record<number, string[]>>({});
  const runStatusRef = useRef<Record<number, string>>({});

  const editStructuredCv = useCallback((next: React.SetStateAction<StructuredCvProfile>) => {
    setStructuredCv(next);
    setProfileDirty(true);
  }, []);

  const loadExtractionRuns = useCallback(async () => {
    try {
      const response = await api.get<ExtractionRun[]>("/profile-cv/runs");
      setExtractionRuns(response.data ?? []);
    } catch {
      // Polling failure must not clear existing run state or touch unsaved profile edits.
    }
  }, []);

  const loadProfile = useCallback(async () => {
    setLoading(true);
    try {
      // /career reads the structured profile from the relational source of truth (/career/profile);
      // /auth/me still provides the account row (avatar, provider chips) shown in the header.
      const [careerResponse, meResponse] = await Promise.all([
        api.get<CareerProfileResponse>("/career/profile"),
        api.get<MeResponse>("/auth/me"),
      ]);
      setMe(meResponse.data);
      setProfileCvText(careerResponse.data?.cvText ?? "");
      const profile = normalizeStructuredCv(careerResponse.data?.profile ?? emptyStructuredCv());
      setStructuredCv(profile);
      setCompleteness(careerResponse.data?.completeness ?? null);
      setProfileDirty(false);
      setHeadline(profile.contact.headline ?? "");
      setLoadError(null);
    } catch (error: any) {
      setMe(null);
      setLoadError(String(error?.response?.data || error?.message || t("profileLoadFailed")));
    } finally {
      setLoading(false);
    }
  }, [t]);

  useEffect(() => {
    void loadProfile();
    void loadExtractionRuns();
    void loadVersions();
  }, [loadExtractionRuns, loadProfile, loadVersions]);

  useEffect(() => {
    const activeRuns = extractionRuns.filter((run) => run.operation
      ? activeOperationStatuses.has(run.operation.status)
      : run.status === "queued" || run.status === "running");
    if (activeRuns.length === 0) return;

    const timer = window.setInterval(() => {
      void loadExtractionRuns();
    }, 4000);

    return () => window.clearInterval(timer);
  }, [extractionRuns, loadExtractionRuns]);

  useEffect(() => {
    const pending = extractionRuns.filter((run) => run.status === "pending_review" && !runDiffs[run.id]);
    if (pending.length === 0) return;
    void Promise.all(pending.map((run) => api.get<CvRunDiffResponse>(`/profile-cv/runs/${run.id}/diff`)))
      .then((responses) => setRunDiffs((current) => Object.fromEntries([
        ...Object.entries(current),
        ...responses.map((response) => [response.data.runId, response.data.diff]),
      ])))
      .catch(() => undefined);
  }, [extractionRuns, runDiffs]);

  useEffect(() => {
    const previous = runStatusRef.current;
    for (const run of extractionRuns) {
      const status = cvRunStatus(run);
      const prior = previous[run.id];
      if (activeRunLabels.has(prior) && status === "pending_review") {
        toast(t("profileCvRunReady", { trigger: run.trigger }), "info");
      }
      if (activeRunLabels.has(prior) && status === "failed") {
        toast(run.errorMessage || t("profileCvRunFailed", { trigger: run.trigger }), "error");
      }
      previous[run.id] = status;
    }
  }, [extractionRuns, t, toast]);

  // Field-review lookup passed to the extracted sections. They stay decoupled from the full profile
  // shape; the parent still owns structuredCv and the metadata source.
  const metaFor = useCallback((path: string) => getStructuredCvFieldMetadata(structuredCv, path), [structuredCv]);

  const initials = useMemo(() => initialsFrom([me?.displayName, me?.firstName, me?.lastName, me?.userName, me?.email]), [me]);
  const isLocal = me?.provider === "local";
  const fullName = [me?.firstName, me?.lastName].filter(Boolean).join(" ");
  const cvWordCount = profileCvText.trim() ? profileCvText.trim().split(/\s+/).length : 0;

  const providerLabel = me?.provider === "local" ? t("profileLocalAccount") : me?.provider === "google" ? t("profileGoogleSession") : t("profileExternalSession");
  const googleLabel = me?.googleLink?.linked
    ? me.googleLink.email
      ? t("profileGoogleLinkedWithEmail", { email: me.googleLink.email })
      : t("profileGoogleLinked")
    : t("profileGoogleNotLinked");
  const cvLabel = profileCvText.trim() ? t("profileCvReady", { count: cvWordCount }) : t("profileCvMissing");
  const latestRun = extractionRuns[0];
  return (
    <Box sx={{ display: "grid", gap: 2 }}>
      <Paper component="nav" aria-label={t("careerWorkspaceNavigation")} variant="outlined" sx={{ borderRadius: 3, overflow: "hidden" }}>
        <FormControl size="small" fullWidth sx={{ display: { xs: "flex", sm: "none" }, p: 1.25 }}>
          <InputLabel id="career-workspace-section-label" sx={{ ml: 1.25 }}>{t("careerWorkspaceNavigation")}</InputLabel>
          <Select
            labelId="career-workspace-section-label"
            value={workspaceSection}
            label={t("careerWorkspaceNavigation")}
            onChange={(event) => navigateWorkspace(event.target.value as CareerWorkspaceSection)}
          >
            <MenuItem value="overview">{t("careerWorkspaceOverviewTab")}</MenuItem>
            <MenuItem value="profile">{t("careerWorkspaceProfileTab")}</MenuItem>
            <MenuItem value="import">{t("careerWorkspaceImportTab")}</MenuItem>
          </Select>
        </FormControl>
        <Tabs
          value={workspaceSection}
          onChange={(_, value: CareerWorkspaceSection) => navigateWorkspace(value)}
          aria-label={t("careerWorkspaceNavigation")}
          sx={{ display: { xs: "none", sm: "flex" }, px: 1 }}
        >
          <Tab value="overview" label={t("careerWorkspaceOverviewTab")} />
          <Tab value="profile" label={t("careerWorkspaceProfileTab")} />
          <Tab value="import" label={t("careerWorkspaceImportTab")} />
        </Tabs>
      </Paper>

      {workspaceSection === "overview" ? (
        <CareerWorkspaceOverview
          completeness={completeness}
          runs={extractionRuns}
          loading={loading}
          loadError={loadError}
          onNavigate={navigateWorkspace}
        />
      ) : null}

      {workspaceSection !== "overview" ? <Paper id={workspaceSection === "profile" ? "career-profile-editor" : "career-cv-import"} sx={{ mt: 0, p: { xs: 1.5, sm: 2.5 }, borderRadius: 4, border: "none", boxShadow: "0px 1px 2px 0px rgba(15,23,42,0.04), 0px 8px 24px -12px rgba(15,23,42,0.12)", scrollMarginTop: 96 }}>
      {workspaceSection === "profile" ? <ProfileCompleteness
        completeness={completeness}
        versions={versions}
        loading={loading}
        onRestore={(version) => void restoreVersion(version)}
        showSummary={false}
      /> : null}
      {workspaceSection === "profile" ? <CropImageDialog
        open={cropOpen}
        file={avatarFile}
        onClose={() => {
          setCropOpen(false);
          setAvatarFile(null);
        }}
        onSave={async (blob) => {
          const file = new File([blob], "avatar.png", { type: "image/png" });
          const formData = new FormData();
          formData.append("file", file);
          setUploadingAvatar(true);
          try {
            const response = await api.post<{ avatarImageDataUrl?: string }>("/auth/avatar", formData, {
              headers: { "Content-Type": "multipart/form-data" },
            });
            setMe((prev) => (prev ? { ...prev, avatarImageDataUrl: response.data?.avatarImageDataUrl ?? prev.avatarImageDataUrl } : prev));
            setCropOpen(false);
            setAvatarFile(null);
            toast(t("profileImageUpdated"), "success");
          } catch (e: any) {
            toast(String(e?.response?.data || e?.message || t("profileImageUploadFailed")), "error");
          } finally {
            setUploadingAvatar(false);
          }
        }}
      /> : null}

      {loadError ? (
        <Alert severity="error" sx={{ mb: 2, borderRadius: 2.5 }} action={<Button color="inherit" size="small" onClick={() => void loadProfile()}>{t("retry")}</Button>}>
          {t("profileLoadFailed")}
          <Typography variant="body2" sx={{ mt: 0.5 }}>{loadError}</Typography>
        </Alert>
      ) : null}

      {workspaceSection === "profile" ? <Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, flexWrap: "wrap" }}>
        <Box sx={{ display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap" }}>
          <Box sx={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 1 }}>
            <Avatar src={me?.avatarImageDataUrl || undefined} sx={{ width: 84, height: 84, fontWeight: 900, fontSize: 28 }}>{initials}</Avatar>
            <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", justifyContent: "center" }}>
              <input
                ref={avatarInputRef}
                type="file"
                accept={AVATAR_UPLOAD_ACCEPT}
                style={{ display: "none" }}
                onChange={(event) => {
                  const file = event.target.files?.[0] ?? null;
                  event.target.value = "";
                  if (!file) return;
                  setAvatarFile(file);
                  setCropOpen(true);
                }}
              />
              <Button variant="outlined" size="small" startIcon={<PhotoCameraOutlinedIcon />} disabled={!isLocal || uploadingAvatar} onClick={() => avatarInputRef.current?.click()}>
                {uploadingAvatar ? t("profileUploading") : t("profileChangeImage")}
              </Button>
              {me?.avatarImageDataUrl ? (
                <Button
                  variant="text"
                  size="small"
                  color="inherit"
                  startIcon={<DeleteOutlineIcon />}
                  disabled={!isLocal || uploadingAvatar}
                  onClick={async () => {
                    setUploadingAvatar(true);
                    try {
                      await api.delete("/auth/avatar");
                      setMe((prev) => (prev ? { ...prev, avatarImageDataUrl: undefined } : prev));
                      toast(t("profileImageRemoved"), "success");
                    } catch (e: any) {
                      toast(String(e?.response?.data || e?.message || t("profileImageRemoveFailed")), "error");
                    } finally {
                      setUploadingAvatar(false);
                    }
                  }}
                >
                  {t("profileRemoveImage")}
                </Button>
              ) : null}
            </Box>
          </Box>
          <Box>
            <Typography variant="h5" sx={{ fontWeight: 900 }}>
              {careerOnly ? t("careerWorkspaceProfileTab") : t("profileTitle")}
            </Typography>
            <Typography sx={{ color: "text.secondary" }}>{me?.userName || me?.displayName || fullName || me?.email || "-"}</Typography>
            <Typography variant="body2" sx={{ color: "text.secondary" }}>{headline || t("profileHeadlinePlaceholder")}</Typography>
          </Box>
        </Box>
        <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", alignItems: "flex-start" }}>
          <Chip label={providerLabel} color={me?.provider === "local" ? "primary" : "default"} />
          <Chip label={googleLabel} color={me?.googleLink?.linked ? "success" : "default"} variant={me?.googleLink?.linked ? "filled" : "outlined"} />
          <Chip label={cvLabel} color={profileCvText.trim() ? "success" : "warning"} variant={profileCvText.trim() ? "filled" : "outlined"} />
        </Box>
      </Box> : null}


      <Box sx={{ mt: 3, display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 2 }}>


        <Box sx={{ gridColumn: "1 / -1", p: workspaceSection === "import" ? { xs: 1.5, sm: 2 } : 0, borderRadius: 3, border: workspaceSection === "import" ? "1px solid" : "none", borderColor: "divider", backgroundColor: workspaceSection === "import" ? "background.default" : "transparent", display: careerOnly ? "block" : "none" }}>
          <Box sx={{ display: workspaceSection === "import" ? "block" : "none" }}>
          {!canUseAi && (
            <Box sx={{ mb: 2 }}>
              <ProFeatureNotice featureKey="career-ai" title={t("profileProImportTitle")}>
                {t("profileProImportBody")}
              </ProFeatureNotice>
            </Box>
          )}
          {profileDirty ? <Alert severity="warning" sx={{ mb: 2 }}>{t("profileUnsavedBeforeActions")}</Alert> : null}
          <Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, flexWrap: "wrap", alignItems: "center", mb: 1.5 }}>
            <Box>
              <Typography variant="h6">{t("profileMasterCv")}</Typography>
              <Typography variant="body2" sx={{ color: "text.secondary" }}>
                {t("profileMasterCvBody")}
              </Typography>
            </Box>
            <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
              <input
                ref={cvInputRef}
                type="file"
                accept={CV_UPLOAD_ACCEPT}
                style={{ display: "none" }}
                onChange={async (event) => {
                  const file = event.target.files?.[0];
                  event.target.value = "";
                  if (!file) return;
                  const formData = new FormData();
                  formData.append("file", file);
                  setUploadingCv(true);
                  try {
                    const res = await api.post<QueuedCvRunResponse>("/profile-cv/upload", formData, { headers: { "Content-Type": "multipart/form-data" } });
                    await loadExtractionRuns();
                    toast(t("profileCvQueuedUpload", { id: res.data.extractionRunId }), "info");
                  } catch (e: any) {
                    toast(String(e?.response?.data || e?.message || t("profileCvUploadFailed")), "error");
                  } finally {
                    setUploadingCv(false);
                  }
                }}
              />
              <Button variant="outlined" disabled={!canUseAi || !isLocal || uploadingCv || improvingCv || rebuildingCv} onClick={() => cvInputRef.current?.click()}>
                {uploadingCv ? t("profileUploading") : t("profileUploadCv")}
              </Button>
              <Button
                variant="outlined"
                disabled={!canUseAi || !isLocal || profileDirty || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
                onClick={async () => {
                  setRebuildingCv(true);
                  try {
                    const res = await api.post<QueuedCvRunResponse>("/profile-cv/rebuild");
                    await loadExtractionRuns();
                    toast(t("profileCvQueuedRebuild", { id: res.data.extractionRunId }), "info");
                  } catch (e: any) {
                    toast(String(e?.response?.data || e?.message || t("profileCvRebuildFailed")), "error");
                  } finally {
                    setRebuildingCv(false);
                  }
                }}
              >
                {rebuildingCv ? t("profileCvRebuilding") : t("profileCvRebuild")}
              </Button>
              <Button
                variant="outlined"
                disabled={!canUseAi || !isLocal || profileDirty || !profileCvText.trim() || uploadingCv || improvingCv || rebuildingCv}
                onClick={async () => {
                  setImprovingCv(true);
                  try {
                    const res = await api.post<QueuedCvRunResponse>("/profile-cv/improve");
                    await loadExtractionRuns();
                    toast(t("profileCvQueuedImprove", { id: res.data.extractionRunId }), "info");
                  } catch (e: any) {
                    toast(String(e?.response?.data || e?.message || t("profileCvImproveFailed")), "error");
                  } finally {
                    setImprovingCv(false);
                  }
                }}
              >
                {improvingCv ? t("profileCvImproving") : t("profileCvImprove")}
              </Button>
              <Button
                variant="outlined"
                disabled={!canUseAi || !isLocal || uploadingCv || improvingCv || rebuildingCv || reprocessingCv || !latestRun}
                onClick={async () => {
                  setReprocessingCv(true);
                  try {
                    const res = await api.post<QueuedCvRunResponse>("/profile-cv/reprocess");
                    await loadExtractionRuns();
                    toast(t("profileCvQueuedReprocess", { id: res.data.extractionRunId }), "info");
                  } catch (e: any) {
                    toast(String(e?.response?.data || e?.message || t("profileCvReprocessFailed")), "error");
                  } finally {
                    setReprocessingCv(false);
                  }
                }}
              >
                {reprocessingCv ? t("profileCvReprocessing") : t("profileCvReprocess")}
              </Button>
            </Box>
          </Box>
          {uploadingCv ? <LinearProgress sx={{ mb: 1.5 }} /> : null}
          <Alert severity="info" sx={{ mb: 2, borderRadius: 2.5 }}>
            {t("profileCvStructuredDefaultHint")}
          </Alert>
          <Accordion disableGutters elevation={0} sx={{ mb: 2, borderRadius: 3, border: "1px solid", borderColor: "divider", backgroundColor: "background.paper", "&:before": { display: "none" } }}>
            <AccordionSummary expandIcon={<ExpandMoreIcon />}>
              <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1.5, alignItems: "center", width: "100%", pr: 1 }}>
                <Box>
                  <Typography variant="subtitle1" sx={{ fontWeight: 800 }}>{t("profileCvRawPanelTitle")}</Typography>
                  <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvRawPanelHelp")}</Typography>
                </Box>
                <Chip size="small" label={t("profileCvSectionWordCount", { count: cvWordCount })} />
              </Box>
            </AccordionSummary>
            <AccordionDetails>
              <TextField
                label={t("profileCvTextLabel")}
                value={profileCvText}
                onChange={(e) => { setProfileCvText(e.target.value); setProfileDirty(true); }}
                helperText={t("profileCvTextHelp")}
                multiline
                minRows={12}
                disabled={!isLocal}
                fullWidth
              />
              <Box sx={{ mt: 1.5, display: "flex", justifyContent: "flex-end" }}>
                <Button variant="text" disabled={!profileCvText.trim()} onClick={() => navigator.clipboard.writeText(profileCvText)}>
                  {t("profileCopyCvText")}
                </Button>
              </Box>
            </AccordionDetails>
          </Accordion>
          <Box sx={{ mt: 2, p: 1.5, borderRadius: 3, border: "1px solid", borderColor: "divider", backgroundColor: "background.paper" }}>
            <Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, flexWrap: "wrap", alignItems: "center", mb: 1.5 }}>
              <Box>
                <Typography variant="subtitle1" sx={{ fontWeight: 800 }}>{t("profileCvExtractionHistory")}</Typography>
                <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvExtractionHistoryHelp")}</Typography>
              </Box>
              {structuredCv.metadata.profileVersion ? <Chip label={t("profileCvProfileVersion", { count: structuredCv.metadata.profileVersion })} size="small" /> : null}
            </Box>
            {latestRun ? (
              <Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 1.25 }}>
                {extractionRuns.map((run) => (
                  <Box key={run.id} sx={{ p: 1.25, borderRadius: 2.5, border: "1px solid", borderColor: run.id === structuredCv.metadata.appliedExtractionRunId ? "primary.main" : "divider", backgroundColor: "background.default" }}>
                    <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap", alignItems: "center", mb: 0.75 }}>
                      <Typography variant="overline">{run.trigger}</Typography>
                      <Box sx={{ display: "flex", gap: 0.75, flexWrap: "wrap" }}>
                        <Chip size="small" label={cvRunStatus(run)} color={run.status === "applied" ? "success" : run.operation?.status === "failed" || run.status === "failed" ? "error" : "default"} variant={run.status === "applied" ? "filled" : "outlined"} />
                        {run.id === structuredCv.metadata.appliedExtractionRunId ? <Chip size="small" color="primary" label={t("profileCvCurrentRun")} /> : null}
                      </Box>
                    </Box>
                    <Typography variant="body2" sx={{ color: "text.secondary" }}>{run.artifactFileName || t("profileCvNoStoredArtifact")}</Typography>
                    <Typography variant="caption" sx={{ color: "text.secondary", display: "block", mt: 0.75 }}>
                      {run.parserVersion} · {new Date(run.startedAtUtc).toLocaleString(language === "nb" ? "nb-NO" : "en")}
                    </Typography>
                    {run.errorMessage ? (
                      <Typography variant="caption" sx={{ color: "error.main", display: "block", mt: 0.75 }}>
                        {run.errorMessage}
                      </Typography>
                    ) : null}
                    {run.operation?.canCancel ? (
                      <Button size="small" color="inherit" sx={{ mt: 0.75 }} onClick={async () => {
                        try {
                          await api.post(`/operations/${run.operation!.id}/cancel`);
                          await loadExtractionRuns();
                          toast(t("profileCvCancelRequested"), "info");
                        } catch (error) {
                          toast(getApiErrorMessage(error, t("profileCvCancelFailed")), "error");
                        }
                      }}>{t("profileCvCancelProcessing")}</Button>
                    ) : null}
                    {run.operation?.canRetry ? (
                      <Button size="small" color="inherit" sx={{ mt: 0.75 }} onClick={async () => {
                        try {
                          await api.post(`/operations/${run.operation!.id}/retry`);
                          await loadExtractionRuns();
                          toast(t("profileCvRetryQueued"), "info");
                        } catch (error) {
                          toast(getApiErrorMessage(error, t("profileCvRetryFailed")), "error");
                        }
                      }}>{t("profileCvRetryProcessing")}</Button>
                    ) : null}
                    {run.status === "pending_review" ? (
                      <Box sx={{ mt: 1.25 }}>
                        {runDiffs[run.id] ? (
                          <>
                            <Typography variant="body2" sx={{ fontWeight: 700 }}>
                              {t("profileCvDiffSummary", { added: runDiffs[run.id].totalAdded, updated: runDiffs[run.id].totalUpdated })}
                              {runDiffs[run.id].totalLowConfidence ? ` | ${t("profileCvNeedAttention", { count: runDiffs[run.id].totalLowConfidence })}` : ""}
                            </Typography>
                            <Typography variant="caption" sx={{ color: "text.secondary", display: "block", mt: 0.5 }}>
                              {runDiffs[run.id].categories
                                .filter((category) => category.added.length || category.updated.length)
                                .map((category) => `${category.category}: +${category.added.length} / ~${category.updated.length}`)
                                .join(" | ") || t("profileCvNoChangesFound")}
                            </Typography>
                          </>
                        ) : <LinearProgress sx={{ my: 1 }} />}
                        {runDiffs[run.id]?.categories.flatMap((category) => [...category.added, ...category.updated].map((change) => ({ ...change, category: category.category }))).filter((change) => change.confidence === "Low").map((change) => (
                          <FormControlLabel
                            key={change.id}
                            sx={{ display: "flex", mt: 0.5 }}
                            control={<Checkbox size="small" checked={(acceptedLowConfidenceIds[run.id] ?? []).includes(change.id)} onChange={(event) => setAcceptedLowConfidenceIds((current) => ({
                              ...current,
                              [run.id]: event.target.checked
                                ? [...(current[run.id] ?? []), change.id]
                                : (current[run.id] ?? []).filter((id) => id !== change.id),
                            }))} />}
                            label={t("profileCvIncludeLowConfidence", { category: change.category, label: change.label })}
                          />
                        ))}
                        {profileDirty ? (
                          <Alert severity="warning" sx={{ mt: 1 }}>
                            {t("profileCvSaveBeforeImport")}
                          </Alert>
                        ) : null}
                        <Box sx={{ display: "flex", gap: 1, mt: 1, flexWrap: "wrap" }}>
                          <Button size="small" variant="contained" disabled={!runDiffs[run.id] || reviewingRunId !== null || profileDirty} onClick={async () => {
                            setReviewingRunId(run.id);
                            try {
                              await api.post(`/profile-cv/runs/${run.id}/accept`, { acceptedLowConfidenceIds: acceptedLowConfidenceIds[run.id] ?? [] });
                              setRunDiffs((current) => { const next = { ...current }; delete next[run.id]; return next; });
                              await Promise.all([loadProfile(), loadExtractionRuns(), loadVersions()]);
                              toast(t("profileCvChangesApplied"), "success");
                            } catch (error) {
                              toast(getApiErrorMessage(error, t("profileCvApplyChangesFailed")), "error");
                            } finally { setReviewingRunId(null); }
                          }}>{t("profileCvApplyChanges")}</Button>
                          <Button size="small" color="inherit" disabled={reviewingRunId !== null} onClick={async () => {
                            setReviewingRunId(run.id);
                            try {
                              await api.post(`/profile-cv/runs/${run.id}/discard`);
                              setRunDiffs((current) => { const next = { ...current }; delete next[run.id]; return next; });
                              await loadExtractionRuns();
                              toast(t("profileCvExtractionDiscarded"), "info");
                            } catch (error) {
                              toast(getApiErrorMessage(error, t("profileCvDiscardFailed")), "error");
                            } finally { setReviewingRunId(null); }
                          }}>{t("profileCvDiscard")}</Button>
                        </Box>
                      </Box>
                    ) : null}
                  </Box>
                ))}
              </Box>
            ) : (
              <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvExtractionHistoryEmpty")}</Typography>
            )}
          </Box>
          <Box sx={{ gridColumn: "1 / -1", display: "flex", justifyContent: "flex-end", mt: 1 }}>
            <Button size="small" variant="text" color="inherit" onClick={() => setShowAdvancedCvTools((v) => !v)}>
              {showAdvancedCvTools ? t("profileCvHideAdvancedTools") : t("profileCvAdvancedTools")}
            </Button>
          </Box>
          <Box sx={{ mt: 2, p: 1.5, borderRadius: 3, border: "1px solid", borderColor: "divider", backgroundColor: "background.paper", display: showAdvancedCvTools ? "block" : "none" }}>
            <Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, flexWrap: "wrap", alignItems: "center", mb: 1.5 }}>
              <Box>
                <Typography variant="subtitle1" sx={{ fontWeight: 800 }}>{t("profileCvStructureOverview")}</Typography>
                <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvStructureOverviewHelp")}</Typography>
              </Box>
              <Button
                variant="outlined"
                disabled={!isLocal || !profileCvText.trim() || parsingCvSections}
                onClick={async () => {
                  setParsingCvSections(true);
                  try {
                    const res = await api.post<{ structuredCv?: StructuredCvProfile }>("/profile-cv/parse", { text: profileCvText });
                    editStructuredCv(normalizeStructuredCv(res.data?.structuredCv));
                    toast(t("profileCvStructureParsed"), "success");
                  } catch (e: any) {
                    toast(String(e?.response?.data || e?.message || t("profileCvStructureParseFailed")), "error");
                  } finally {
                    setParsingCvSections(false);
                  }
                }}
              >
                {parsingCvSections ? t("profileCvStructureParsing") : t("profileCvStructureParse")}
              </Button>
            </Box>
            {structuredCv.sections.length > 0 ? (
              <Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 1.5 }}>
                {structuredCv.sections.map((section) => {
                  const safeContent = typeof section.content === "string" ? section.content : "";
                  const safeWordCount = Number.isFinite(Number(section.wordCount)) ? Number(section.wordCount) : (safeContent.trim() ? safeContent.trim().split(/\s+/).length : 0);
                  return (
                    <Box key={section.name} sx={{ p: 1.25, borderRadius: 2.5, border: "1px solid", borderColor: "divider", backgroundColor: "background.default" }}>
                      <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, alignItems: "center", mb: 0.75 }}>
                        <Typography variant="overline">{section.name}</Typography>
                        <Chip size="small" label={t("profileCvSectionWordCount", { count: safeWordCount })} />
                      </Box>
                      <Typography variant="body2" sx={{ color: "text.secondary", whiteSpace: "pre-wrap" }}>{safeContent.slice(0, 280)}{safeContent.length > 280 ? "…" : ""}</Typography>
                    </Box>
                  );
                })}
              </Box>
            ) : (
              <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvStructureEmpty")}</Typography>
            )}
          </Box>
          </Box>
          <Box sx={{ mt: workspaceSection === "profile" ? 2 : 0, p: 1.5, borderRadius: 3, border: "1px solid", borderColor: "divider", backgroundColor: "background.paper", display: workspaceSection === "profile" ? "block" : "none" }}>
            <Box sx={{ mb: 1.5 }}>
              <Typography variant="subtitle1" sx={{ fontWeight: 800 }}>{t("profileCvStructuredEditor")}</Typography>
              <Typography variant="body2" sx={{ color: "text.secondary" }}>{t("profileCvStructuredEditorHelp")}</Typography>
            </Box>

            <PersonalInformationSection
              value={structuredCv.contact}
              onChange={(next) => editStructuredCv((prev) => ({ ...prev, contact: next }))}
              getMetadata={metaFor}
            />

            <Box sx={{ mt: 2, display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 1.5 }}>
              <ProfessionalSummarySection value={structuredCv.summary} onChange={(next) => editStructuredCv((prev) => ({ ...prev, summary: next }))} getMetadata={metaFor} />
              <SkillsSection value={structuredCv.skills} onChange={(next) => editStructuredCv((prev) => ({ ...prev, skills: next }))} getMetadata={metaFor} />
              <InterestsSection value={structuredCv.interests} onChange={(next) => editStructuredCv((prev) => ({ ...prev, interests: next }))} getMetadata={metaFor} />
            </Box>

            <LongTailSections values={{ awards: structuredCv.awards, publications: structuredCv.publications, organisations: structuredCv.organisations, references: structuredCv.references }} onChange={(key, next) => editStructuredCv((prev) => ({ ...prev, [key]: next }))} />

            <LanguagesSection value={structuredCv.languages} onChange={(next) => editStructuredCv((prev) => ({ ...prev, languages: next }))} getMetadata={metaFor} />

            <WorkExperienceSection value={structuredCv.jobs} onChange={(next) => editStructuredCv((prev) => ({ ...prev, jobs: next }))} />

            <EducationSection value={structuredCv.education} onChange={(next) => editStructuredCv((prev) => ({ ...prev, education: next }))} />

            <OtherSectionsSection value={structuredCv.otherSections} onChange={(next) => editStructuredCv((prev) => ({ ...prev, otherSections: next }))} />
          </Box>
          <Box sx={{ mt: 1, display: workspaceSection === "profile" ? "flex" : "none", justifyContent: "space-between", gap: 1, flexWrap: "wrap" }}>
            <Typography variant="caption" sx={{ color: "text.secondary" }}>
              {t("profileCvSectionWordCount", { count: cvWordCount })}
            </Typography>
            <Typography variant="caption" sx={{ color: "text.secondary" }}>
              {t("profileCvPreferredUploads")}
            </Typography>
          </Box>
        </Box>

        <Box sx={{ gridColumn: "1 / -1", display: workspaceSection === "profile" ? "flex" : "none", justifyContent: "flex-end", gap: 2, flexWrap: "wrap", alignItems: "center" }}>
          {profileDirty ? <Chip size="small" color="warning" variant="outlined" label={t("assetsUnsavedChanges")} /> : null}
          <Button
            variant="contained"
            disabled={!isLocal || loading}
            onClick={async () => {
              setLoading(true);
              try {
                // Save the master profile through the relational source of truth. The endpoint
                // persists the structured children + version and keeps the legacy blob projection
                // in sync; identity fields are never touched (they belong to /profile).
                const saved = await api.put<CareerProfileResponse>("/career/profile", { profile: structuredCv, cvText: profileCvText });
                setStructuredCv(normalizeStructuredCv(saved.data?.profile ?? structuredCv));
                setCompleteness(saved.data?.completeness ?? null);
                setProfileDirty(false);
                toast(t("profileUpdated"), "success");
              } catch (e: any) {
                const msg = e?.response?.data || e?.message || t("profileUpdateFailed");
                toast(String(msg), "error");
              } finally {
                setLoading(false);
              }
            }}
          >
            {t("profileSaveChanges")}
          </Button>
        </Box>


      </Box>

      </Paper> : null}
    </Box>
  );
}
