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

import { Accordion, AccordionDetails, AccordionSummary, Alert, Avatar, Box, Button, Chip, Dialog, DialogContent, DialogTitle, Divider, FormControl, IconButton, InputLabel, LinearProgress, MenuItem, Paper, Select, 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 ZoomInOutlinedIcon from "@mui/icons-material/ZoomInOutlined";

import { api, getApiErrorMessage } from "../api";
import GoogleAuthCard from "../components/GoogleAuthCard";
import MicrosoftAuthCard from "../components/MicrosoftAuthCard";
import AuthStatusCard from "../components/AuthStatusCard";
import TwoFactorSettingsCard from "../components/TwoFactorSettingsCard";
import SessionsSettingsCard from "../components/SessionsSettingsCard";
import CropImageDialog from "../components/CropImageDialog";
import { useToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";
import {
  emptyStructuredCv,
  getStructuredCvFieldMetadata,
  joinLines,
  normalizeStructuredCv,
  parseStructuredCvJson,
  splitLines,
  StructuredCvFieldMetadata,
  StructuredCvProfile,
} from "../profileCv";
import { JobApplication } from "../types";


type CvSectionOption = "" | "Professional Summary" | "Core Skills" | "Experience Highlights" | "Selected Achievements" | "Projects";
type CvSectionStyle = "ats-minimal" | "harvard" | "auckland" | "edinburgh" | "monarch" | "fjord";

type CvBuilderTone = "Concise and direct" | "Executive and polished" | "Technical and detailed" | "Warm and people-focused";
type CvBuilderLanguage = "English" | "Norwegian" | "Spanish" | "French" | "German";

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

type QueuedCvRunResponse = {
  queued: boolean;
  extractionRunId: number;
  status: string;
};

type JobListResponse = {
  items: JobApplication[];
  total: number;
  page: number;
  pageSize: number;
};

type RewriteTemplateOption = {
  id: CvSectionStyle;
  title: string;
  eyebrow: string;
  accent: string;
  blurb: string;
  sampleHeading: string;
  sampleMeta: string;
  sampleBullets: string[];
};

type CvBuilderPreview = {
  templateId: CvSectionStyle;
  html: string;
  suggestedFileName: string;
  fullText: string;
  rewrittenText: string;
  structuredCv: StructuredCvProfile;
  sectionName?: string | null;
  targetRole?: string | null;
  jobApplicationId?: number | null;
};

type PdfCarouselItem = {
  templateId: CvSectionStyle;
  title: string;
  fileName: string;
  pdfUrl?: string;
  status: "loading" | "ready" | "error";
  error?: string;
};

type RewriteRequestPayload = {
  sectionName: string | null;
  style: CvSectionStyle;
  templateId: CvSectionStyle;
  targetRole: string | null;
  jobApplicationId: number | null;
  sourceText: string | null;
  promptBackground: string | null;
  tone: string | null;
  language: string | null;
};

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";
const REWRITE_TEMPLATES: RewriteTemplateOption[] = [
  {
    id: "ats-minimal",
    title: "ATS Minimal",
    eyebrow: "Scanner-friendly",
    accent: "#0f172a",
    blurb: "Compact, direct, and easy for screening systems to parse.",
    sampleHeading: "Senior Backend Engineer",
    sampleMeta: "Acme Systems · Oslo · 2021 - Present",
    sampleBullets: ["Built API workflows with measurable delivery outcomes.", "Kept skills and achievements easy to scan."]
  },
  {
    id: "harvard",
    title: "Harvard",
    eyebrow: "Traditional",
    accent: "#7f1d1d",
    blurb: "Formal hierarchy and restrained tone for conservative hiring flows.",
    sampleHeading: "Professional Summary",
    sampleMeta: "Clear structure · precise dates · credible language",
    sampleBullets: ["Emphasizes polished summaries.", "Works well for broad professional roles."]
  },
  {
    id: "auckland",
    title: "Auckland",
    eyebrow: "Modern sidebar",
    accent: "#0f766e",
    blurb: "Sharper highlights with a more contemporary, design-forward rhythm.",
    sampleHeading: "Selected Impact",
    sampleMeta: "Focused strengths · compact highlights",
    sampleBullets: ["Pulls skills into stronger highlight clusters.", "Good when you want a fresher feel."]
  },
  {
    id: "edinburgh",
    title: "Edinburgh",
    eyebrow: "Editorial",
    accent: "#5b21b6",
    blurb: "More personality and stronger section contrast without losing clarity.",
    sampleHeading: "Experience Highlights",
    sampleMeta: "Premium spacing · stronger visual voice",
    sampleBullets: ["Useful when the CV should feel more distinctive.", "Still keeps wording grounded and factual."]
  },
  {
    id: "monarch",
    title: "Monarch",
    eyebrow: "Executive",
    accent: "#7c2d12",
    blurb: "High-contrast premium presentation for leadership-heavy applications.",
    sampleHeading: "Executive Profile",
    sampleMeta: "Leadership clarity · premium hierarchy",
    sampleBullets: ["Adds more top-level summary emphasis.", "Well suited to senior strategic roles."]
  },
  {
    id: "fjord",
    title: "Fjord",
    eyebrow: "Technical",
    accent: "#0f4c5c",
    blurb: "Calm, high-density layout for engineering resumes and project-heavy CVs.",
    sampleHeading: "Projects & Systems",
    sampleMeta: "Technical depth · practical readability",
    sampleBullets: ["Gives projects and skills more weight.", "Better for technical detail without chaos."]
  },
];

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();
}

function confidenceTone(confidence?: number) {
  if (typeof confidence !== "number") return { label: "Review", color: "default" as const };
  if (confidence >= 0.8) return { label: `High ${Math.round(confidence * 100)}%`, color: "success" as const };
  if (confidence >= 0.65) return { label: `Medium ${Math.round(confidence * 100)}%`, color: "warning" as const };
  return { label: `Low ${Math.round(confidence * 100)}%`, color: "error" as const };
}

function FieldReviewNote({ metadata }: { metadata?: StructuredCvFieldMetadata }) {
  if (!metadata) return null;
  const tone = confidenceTone(metadata.confidence);
  return (
    <Box sx={{ display: "flex", gap: 0.75, flexWrap: "wrap", mt: 0.75, alignItems: "center" }}>
      <Chip size="small" color={tone.color} variant={tone.color === "default" ? "outlined" : "filled"} label={tone.label} />
      {metadata.method ? <Chip size="small" variant="outlined" label={metadata.method} /> : null}
      {metadata.sourceBlockId ? <Chip size="small" variant="outlined" label={metadata.sourceBlockId} /> : null}
      {metadata.reviewState ? <Chip size="small" variant="outlined" label={metadata.reviewState} /> : null}
      {metadata.sourceSnippet ? (
        <Typography variant="caption" sx={{ color: "text.secondary" }}>
          {metadata.sourceSnippet}
        </Typography>
      ) : null}
    </Box>
  );
}

// ProfilePage backs /profile: account identity + security + preferences. The master career
// profile lives in CareerProfilePage (/career). Split in Phase 2.2. Saves only identity fields
// (partial update), never the master profile.
export default function ProfilePage() {
  // Retained so the shared JSX reads identically; hardcoded for /profile.
  const careerOnly = false;
  const { toast } = useToast();
  const { t } = useI18n();
  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 [uploadingAvatar, setUploadingAvatar] = useState(false);
  const [avatarFile, setAvatarFile] = useState<File | null>(null);
  const [cropOpen, setCropOpen] = useState(false);

  const [email, setEmail] = useState("");
  const [userName, setUserName] = useState("");
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [displayName, setDisplayName] = useState("");
  const [headline, setHeadline] = useState("");
  const [profileCvText, setProfileCvText] = useState("");
  const [currentPassword, setCurrentPassword] = useState("");
  const [newPassword, setNewPassword] = useState("");


  const loadProfile = useCallback(async () => {
    setLoading(true);
    try {
      // /profile only needs the account row. The master-profile data (runs, structured CV,
      // saved jobs) is loaded by CareerProfilePage on /career.
      const r = await api.get<MeResponse>("/auth/me");
      setMe(r.data);
      setEmail(r.data?.email ?? "");
      setUserName(r.data?.userName ?? "");
      setFirstName(r.data?.firstName ?? "");
      setLastName(r.data?.lastName ?? "");
      setDisplayName(r.data?.displayName ?? "");
      setProfileCvText(r.data?.profileCvText ?? "");
      setHeadline(window.localStorage.getItem("profileHeadline") ?? "");
      setLoadError(null);
    } catch (error: any) {
      setMe(null);
      setLoadError(String(error?.response?.data || error?.message || "Unable to load profile right now."));
    } finally {
      setLoading(false);
    }
  }, []);

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

  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");

  return (
    <Paper sx={{ mt: 0, p: 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)" }}>
      <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);
          }
        }}
      />

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

      <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 ? "Master career profile" : 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>

      {!careerOnly ? <>
        <AuthStatusCard />
        <GoogleAuthCard />
        <MicrosoftAuthCard />
      </> : null}

      <Box sx={{ mt: 3, display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 2 }}>
        {!careerOnly ? <Box sx={{ gridColumn: "1 / -1" }}>
          <Typography variant="h6">{t("profileAccountSection")}</Typography>
          {!isLocal ? (
            <Alert severity="info" sx={{ mt: 1 }}>
              {t("profileReadOnlyInfo")}
            </Alert>
          ) : null}
        </Box> : null}

        {!careerOnly ? <>
          <TextField label={t("profileDisplayName")} value={displayName} onChange={(e) => setDisplayName(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField label={t("profileUsername")} value={userName} onChange={(e) => setUserName(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField label={t("profileFirstName")} value={firstName} onChange={(e) => setFirstName(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField label={t("profileLastName")} value={lastName} onChange={(e) => setLastName(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField label={t("profileEmail")} value={email} onChange={(e) => setEmail(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField
          label={t("profileHeadline")}
          value={headline}
          onChange={(e) => setHeadline(e.target.value)}
          helperText={t("profileHeadlineHelp")}
          fullWidth
          />
        </> : null}


        <Box sx={{ gridColumn: "1 / -1", display: "flex", justifyContent: "flex-end", gap: 2, flexWrap: "wrap", alignItems: "center" }}>
          <Button
            variant="contained"
            disabled={!isLocal || loading}
            onClick={async () => {
              setLoading(true);
              try {
                // /profile saves identity only. The backend does partial updates, so omitting the
                // master-profile fields leaves them untouched (they are owned by /career).
                await api.put("/auth/profile", { email, userName, firstName, lastName, displayName });
                window.localStorage.setItem("profileHeadline", headline.trim());
                await loadProfile();
                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>

        {!careerOnly ? <Box sx={{ gridColumn: "1 / -1", mt: 1 }}>
          <Divider sx={{ mb: 2 }} />
          <Typography variant="h6">{t("profileChangePassword")}</Typography>
          {!isLocal ? <Typography sx={{ color: "text.secondary" }}>{t("profilePasswordLocalOnly")}</Typography> : null}
        </Box> : null}

        {!careerOnly ? <>
          <TextField label={t("profileCurrentPassword")} type="password" value={currentPassword} onChange={(e) => setCurrentPassword(e.target.value)} disabled={!isLocal} fullWidth />
          <TextField label={t("profileNewPassword")} type="password" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} disabled={!isLocal} fullWidth />

          <Box sx={{ gridColumn: "1 / -1", display: "flex", justifyContent: "flex-end" }}>
          <Button
            variant="outlined"
            disabled={!isLocal || loading}
            onClick={async () => {
              setLoading(true);
              try {
                await api.post("/auth/change-password", { currentPassword, newPassword });
                setCurrentPassword("");
                setNewPassword("");
                toast(t("profilePasswordUpdated"), "success");
              } catch (e: any) {
                const msg = e?.response?.data || e?.message || t("profilePasswordUpdateFailed");
                toast(String(msg), "error");
              } finally {
                setLoading(false);
              }
            }}
          >
            {t("profileUpdatePassword")}
          </Button>
          </Box>
        </> : null}
      </Box>

      {!careerOnly && isLocal ? <TwoFactorSettingsCard /> : null}
      {!careerOnly && isLocal ? <SessionsSettingsCard /> : null}
    </Paper>
  );
}
