"use client";

import type { ChangeEvent, ReactNode } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import type { User } from "@supabase/supabase-js";
import { emptyRi, extractRiFromFile, isRiRecent, type RiExtracted } from "../lib/ri-parser";
import { supabase } from "../lib/supabase";
import ComparisonPreview from "./comparison-preview";

type Eligibility = {
  insured: string;
  riStatus: string;
  insurerId: string;
  insurerName: string;
  riRequested: boolean;
};

type InsurerGuide = {
  id: string;
  name: string;
  logoUrl?: string;
  insurer?: string;
  aliases: string[];
  instructions: string;
  phone?: string;
  hours?: string;
  portalUrl?: string;
  sourceUrl?: string;
};

type CallbackForm = {
  firstName: string;
  lastName: string;
  phone: string;
  website: string;
};

type SubscriptionDocumentType = "identity_front" | "identity_back" | "licence_front" | "licence_back" | "registration" | "rib" | "other";

type SubscriptionDocumentRow = {
  id: string;
  dossier_id: string;
  user_id: string;
  document_type: SubscriptionDocumentType;
  file_path: string;
  original_name: string;
  mime_type: string;
  file_size: number;
  uploaded_at: string;
};

type SubscriptionDocumentSlot = {
  type: SubscriptionDocumentType;
  title: string;
  hint: string;
  marker: string;
  imageUrl?: string;
};

type Answers = {
  cardIssueDate: string; registeredHolder: string; acquisition: string; transformed: string;
  usage: string; mileage: string; parkingType: string; parkingPostalCode: string;
  phone: string; maritalStatus: string; profession: string; accompaniedDriving: string;
  householdDrivers: string; householdVehicles: string; housingType: string;
  suspension: string; suspensionDetails: string; alcoholDrugs: string;
  cancellation: string; cancellationDetails: string; protectionPriority: string;
  desiredFormula: string; desiredStartDate: string;
  registration: string; registrationMatchesCard: string; mainDriverName: string;
  mainDriverBirthDate: string; ownerRelationship: string; licenceCountry: string;
  licenceIssueDate: string; accompaniedDrivingType: string; housingTenure: string;
  parkingCollective: string; parkingClosed: string; parkingCovered: string;
  professionOther: string; householdYoungLicences: string; aggravations: string[];
};

type DossierRow = {
  documents_requested_at: string | null;
  id: string; user_id: string; status: string; current_step: number; phone: string | null;
  prospect_email: string | null; workflow_status: string; selected_quote_id: string | null;
  eligibility: Eligibility | null; ri_file_path: string | null; ri_original_name: string | null;
  ri_mime_type: string | null; ri_file_size: number | null; ri_issue_date: string | null;
  ri_extracted: RiExtracted | null; ri_confirmed: boolean; answers: Answers | null;
  consent_data_processing: boolean; consent_accuracy: boolean;
};

type QuoteRow = {
  quote_reference: string | null;
  id: string; dossier_id: string; position: number; insurer_name: string; formula_name: string;
  monthly_premium: number | null; annual_premium: number; guarantees_summary: string;
  deductibles_summary: string; advice: string; valid_until: string | null; file_path: string;
  original_name: string; status: "published" | "selected";
};

const initialEligibility: Eligibility = { insured: "", riStatus: "", insurerId: "", insurerName: "", riRequested: false };

const genericInstructions = "Consultez la rubrique « Assurances » ou « Mes documents » de votre espace client. Si le relevé n’est pas disponible, demandez un relevé d’informations automobile actualisé à votre conseiller ou au service client indiqué sur votre avis d’échéance.";

const insurerGuides: InsurerGuide[] = [
  { id: "direct-assurance", name: "Direct Assurance", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Direct-Assurance.jpeg", aliases: ["direct", "axa direct"], instructions: "Demandez votre relevé depuis l’application ou votre espace personnel Direct Assurance. Vous pouvez également contacter le service client.", phone: "09 70 80 80 04", hours: "Du lundi au vendredi de 8 h 30 à 19 h et le samedi de 9 h à 16 h", portalUrl: "https://www.direct-assurance.fr/nos-services/contactez-nous", sourceUrl: "https://www.direct-assurance.fr/direct-assurance/a-propos" },
  { id: "banque-postale", name: "La Banque Postale", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-LA-BANQUE-POSTALE.png", aliases: ["lbp", "banque postale", "la banque postale assurances iard"], instructions: "Demandez votre relevé au Centre financier ou au Service Client de La Banque Postale.", phone: "02 28 09 42 00", hours: "Du lundi au vendredi de 9 h à 18 h 30 et le samedi de 8 h 45 à 13 h · Centre financier : 3639", portalUrl: "https://www.labanquepostale.fr/particulier/faq-centre-aide/assurances/assurance-vehicule.question.html/quelles-sont-les-demarches-a-effectuer-pour-obtenir-le-releve-d-information-de-mon-assurance-auto.html", sourceUrl: "https://www.labanquepostale.fr/particulier/faq-centre-aide/assurances/assurance-vehicule.question.html/quelles-sont-les-demarches-a-effectuer-pour-obtenir-le-releve-d-information-de-mon-assurance-auto.html" },
  { id: "credit-agricole", name: "Crédit Agricole", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Credit-Agricole.png", insurer: "Pacifica", aliases: ["pacifica", "ca", "credit agricole"], instructions: "Consultez l’application Mes Assurances ou votre espace Crédit Agricole. À défaut, demandez le relevé à votre conseiller bancaire.", portalUrl: "https://www.credit-agricole.fr/particulier/applications/mesassurances.html", sourceUrl: "https://www.credit-agricole.fr/particulier/assurances/auto-2-roues/assurance-auto.html" },
  { id: "lcl", name: "LCL", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-LCL.jpeg", insurer: "Pacifica", aliases: ["pacifica", "credit lyonnais"], instructions: "Consultez votre espace LCL ou l’application LCL Assurances. À défaut, demandez le relevé à votre conseiller.", portalUrl: "https://www.lcl.fr/assurances", sourceUrl: "https://www.lcl.fr/assurer-vehicule/assurance-automobile" },
  { id: "credit-mutuel", name: "Crédit Mutuel", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Credit-mutuel.jpeg", insurer: "ACM", aliases: ["acm", "assurances du credit mutuel"], instructions: "Consultez la rubrique Assurances de votre espace ou application Crédit Mutuel. Vous pouvez également adresser la demande à votre conseiller.", portalUrl: "https://www.creditmutuel.fr/fr/particuliers/assurance/application-assurance.html", sourceUrl: "https://www.creditmutuel.fr/fr/particuliers/assurance/comment-obtenir-attestation.html" },
  { id: "cic", name: "CIC", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-CIC.png", insurer: "ACM", aliases: ["acm", "assurances du credit mutuel"], instructions: "Consultez la rubrique Assurances de votre espace CIC. Si le document n’apparaît pas, contactez votre conseiller en lui demandant expressément un relevé d’informations automobile.", portalUrl: "https://www.cic.fr/fr/particuliers/assurance.html" },
  { id: "banque-populaire", name: "Banque Populaire", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Banque-Populaire.jpeg", insurer: "BPCE Assurances", aliases: ["bpce", "assur-bp", "banque populaire"], instructions: "Téléchargez votre relevé depuis votre espace personnel ou l’application mobile, dans la rubrique Assurances puis le contrat automobile.", portalUrl: "https://www.banquepopulaire.fr/banque-a-distance/mes-assurances/", sourceUrl: "https://www.banquepopulaire.fr/assurer/assurance-auto/releve-information/" },
  { id: "caisse-epargne", name: "Caisse d’Épargne", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Caisse-depargne.jpeg", insurer: "BPCE Assurances", aliases: ["bpce", "caisse d'epargne", "caisse epargne"], instructions: "Récupérez le relevé dans votre espace client ou votre application. Vous pouvez aussi joindre un gestionnaire ou votre conseiller bancaire.", phone: "09 69 36 45 45", hours: "Appel non surtaxé", portalUrl: "https://www.caisse-epargne.fr/banque-a-distance/gerer-vos-assurances-a-distance/", sourceUrl: "https://www.caisse-epargne.fr/faq-particuliers/assurance/gestion/comment-acceder-a-mes-releves-dinformation/" },
  { id: "societe-generale", name: "Société Générale", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Societe-generale.png", insurer: "Sogessur", aliases: ["sg", "sogessur", "societe generale"], instructions: "Demandez votre relevé d’informations auprès d’Allô Contrats Sogessur.", phone: "09 69 32 99 69", hours: "Du lundi au vendredi de 9 h à 19 h et le samedi de 9 h à 17 h", portalUrl: "https://particuliers.sg.fr/assurances/nos-offres/assurance-auto", sourceUrl: "https://particuliers.sg.fr/icd/pch/faq/assurances/assurance-auto/comment-obtenir-un-releve-d-informations-assurance-auto" },
  { id: "bnp-paribas", name: "BNP Paribas", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-bnp-paribas.jpeg", insurer: "Cardif IARD", aliases: ["cardif", "bnp", "bnp paribas"], instructions: "Consultez la rubrique Assurances de votre espace BNP Paribas. Si le relevé n’est pas disponible, demandez-le à votre conseiller ou au service assurance.", portalUrl: "https://mabanque.bnpparibas/fr/assurer/vehicule", sourceUrl: "https://mabanque.bnpparibas/fr/assurer/vehicule/assurance-auto" },
  { id: "allianz", name: "Allianz", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-ALLIANZ.png", aliases: ["allsecur", "allianz direct"], instructions: genericInstructions, portalUrl: "https://www.allianz.fr/assurance-particulier/espace-client.html" },
  { id: "axa", name: "AXA", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-AXA-France.png", aliases: [], instructions: genericInstructions, portalUrl: "https://www.axa.fr/espace-client.html" },
  { id: "gmf", name: "GMF", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-GMF.png", aliases: [], instructions: genericInstructions, portalUrl: "https://www.gmf.fr/" },
  { id: "macif", name: "MACIF", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-MACIF.png", aliases: [], instructions: "Demandez votre relevé par écrit depuis le formulaire de contact de votre Espace Personnel ou par téléphone auprès d’un conseiller.", phone: "09 69 39 49 49", hours: "Du lundi au vendredi de 8 h à 20 h et le samedi de 9 h à 17 h", portalUrl: "https://www.macif.fr/assurance/particuliers/acceder-vos-espaces", sourceUrl: "https://www.macif.fr/assurance/particuliers/faq?question=comment-obtenir-releve-dinformations" },
  { id: "maif", name: "MAIF", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-MAIF.png", aliases: [], instructions: genericInstructions, portalUrl: "https://www.maif.fr/" },
  { id: "matmut", name: "MATMUT", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-MATMUT.png", aliases: [], instructions: "Demandez votre relevé à tout moment depuis votre espace personnel ou l’application Ma Matmut. Vous pouvez aussi effectuer une demande expresse par courrier, e-mail ou téléphone.", phone: "02 35 03 68 68", hours: "Du lundi au vendredi de 8 h à 19 h et le samedi de 9 h à 17 h", portalUrl: "https://www.matmut.fr/app/EspaceSocietaireInternet/", sourceUrl: "https://www.matmut.fr/assurance/auto/conseils/releve-information-assurance-auto-definition" },
  { id: "mma", name: "MMA", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-MMA.jpeg", aliases: [], instructions: genericInstructions, portalUrl: "https://www.mma.fr/" },
  { id: "groupama", name: "Groupama", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-GROUPAMA.png", aliases: ["amaguiz"], instructions: genericInstructions, portalUrl: "https://www.groupama.fr/" },
  { id: "generali", name: "Generali", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-GENERALI.png", aliases: [], instructions: "Demandez votre relevé depuis votre Espace Client. Generali vous l’adressera ensuite par courrier à votre domicile.", portalUrl: "https://www.generali.fr/espace-client/", sourceUrl: "https://www.generali.fr/recherche?q=relev%C3%A9+d%27information" },
  { id: "abeille", name: "Abeille Assurances", logoUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/LOGO-Abeille-assurance.jpeg", aliases: ["aviva"], instructions: "Demandez votre relevé depuis votre Espace Personnel ou le formulaire de contact. Vous pouvez également contacter votre conseiller ou le service client.", phone: "02 32 82 45 02", hours: "Du lundi au vendredi de 8 h 45 à 20 h et le samedi de 9 h à 17 h", portalUrl: "https://www.abeille-assurances.fr/particulier/contact.html", sourceUrl: "https://www.abeille-assurances.fr/particulier/contact.html" },
  ...["ACOMMEASSURE.COM", "ACTE IARD", "Active Assurances", "AG2R La Mondiale", "AGPM", "AIG", "ALOA Assurances", "Altima Assurances", "AMF Assurances", "AMV", "AON", "APRIL", "Aréas Assurances", "ASSU 2000", "Assur One", "Assurance Unie", "Assurance Mutuelle de Picardie", "Assuravenue", "Assurbike", "Assuréo", "Assuronline", "Assurpeople", "Autofirst", "Axeria IARD", "BRED"].map((name, index) => ({ id: `autre-${index}`, name, aliases: [], instructions: genericInstructions })),
  { id: "autre", name: "Autre compagnie", aliases: ["je ne trouve pas", "autre assureur"], instructions: genericInstructions },
];

const riRequestText = "Bonjour, je vous remercie de me transmettre mon relevé d’informations automobile actualisé, daté de moins de trois mois, pour mon contrat n° [numéro du contrat], concernant le véhicule immatriculé [immatriculation]. Cordialement.";
const guaranteeDetails: Record<string, { tagline: string; coverage: string; limitation?: string; image: string; audience: string }> = {
  "Tiers": {
    tagline: "Je protège les autres, pas ma voiture",
    coverage: "C’est le minimum légal. Si vous abîmez la voiture de quelqu’un ou blessez une personne, l’assurance indemnise les tiers. En revanche, votre propre véhicule n’est pas couvert s’il est endommagé, volé ou incendié.",
    image: "Imaginez une protection tournée vers les autres : elle les indemnise, mais ne rembourse pas votre voiture.",
    audience: "Une voiture ancienne ou de faible valeur, que vous pourriez remplacer sans difficulté majeure.",
  },
  "Tiers étendu": {
    tagline: "Les autres + les coups du sort",
    coverage: "Cette formule protège les tiers et ajoute des garanties pour votre voiture en cas de bris de glace, de vol, d’incendie, de catastrophe naturelle, de tempête ou d’événement climatique.",
    limitation: "Votre voiture n’est généralement pas couverte si vous êtes responsable d’un accident : par exemple, si vous heurtez un poteau ou un autre véhicule.",
    image: "Vous ajoutez une protection contre les principaux imprévus, sans aller jusqu’à couvrir tous les dommages accidentels.",
    audience: "Une voiture de valeur moyenne, notamment si elle stationne souvent dehors.",
  },
  "Tous risques": {
    tagline: "Tout le monde est couvert, moi compris, même si c’est ma faute",
    coverage: "Cette formule reprend les garanties du tiers étendu et ajoute les dommages tous accidents : votre propre véhicule peut être couvert lorsque vous êtes responsable ou lorsque le responsable n’est pas identifié, par exemple après un délit de fuite ou un choc sur un parking.",
    image: "C’est la formule la plus protectrice pour votre véhicule, y compris lorsque votre responsabilité est engagée.",
    audience: "Une voiture récente ou neuve, ou un véhicule financé en crédit, LOA ou LLD.",
  },
};
const subscriptionDocumentSlots: SubscriptionDocumentSlot[] = [
  { type: "identity_front", title: "CNI du souscripteur — recto", hint: "Photo ou PDF parfaitement lisible", marker: "CNI", imageUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/CNI-Face-Avant-Recto.png" },
  { type: "identity_back", title: "CNI du souscripteur — verso", hint: "Photo ou PDF parfaitement lisible", marker: "CNI", imageUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/CNI-Face-Arriere-Verso.png" },
  { type: "licence_front", title: "Permis de conduire — recto", hint: "Cadrez l’intégralité du document", marker: "PC", imageUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/PC-Face-Avant-Recto.png" },
  { type: "licence_back", title: "Permis de conduire — verso", hint: "Cadrez l’intégralité du document", marker: "PC", imageUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/PC-Face-Arriere-Verso.png" },
  { type: "registration", title: "Carte grise du véhicule", hint: "Toutes les rubriques doivent être lisibles", marker: "CG", imageUrl: "https://maga-assurances.com/wp-content/uploads/2026/09/Carte-Grise.png" },
  { type: "rib", title: "Relevé d’identité bancaire — RIB", hint: "Compte utilisé par l’assureur pour les prélèvements", marker: "RIB" },
];
const otherDocumentSlot: SubscriptionDocumentSlot = {
  type: "other",
  title: "Autre document",
  hint: "Ajoutez librement une pièce utile à votre dossier",
  marker: "+",
};
const initialAnswers: Answers = {
  cardIssueDate: "", registeredHolder: "", acquisition: "", transformed: "", usage: "",
  mileage: "", parkingType: "", parkingPostalCode: "", phone: "", maritalStatus: "",
  profession: "", accompaniedDriving: "", householdDrivers: "", householdVehicles: "",
  housingType: "", suspension: "", suspensionDetails: "", alcoholDrugs: "", cancellation: "",
  cancellationDetails: "", protectionPriority: "", desiredFormula: "", desiredStartDate: "",
  registration: "", registrationMatchesCard: "", mainDriverName: "", mainDriverBirthDate: "",
  ownerRelationship: "", licenceCountry: "", licenceIssueDate: "", accompaniedDrivingType: "",
  housingTenure: "", parkingCollective: "", parkingClosed: "", parkingCovered: "",
  professionOther: "", householdYoungLicences: "", aggravations: [],
};

const steps = ["Accueil", "Éligibilité", "Accès sécurisé", "Votre relevé", "Carte grise", "Votre situation", "Protection et antécédents", "Vérification", "Confirmation"];
const OTP_LENGTH = 8;

function Choice({ value, current, onClick, children }: { value: string; current: string; onClick: () => void; children: ReactNode }) {
  return <button type="button" className={`choice ${current === value ? "selected" : ""}`} onClick={onClick}>{children}</button>;
}

function SelectField({ label, value, onChange, children, hint, required = true }: { label: string; value: string; onChange: (value: string) => void; children: ReactNode; hint?: string; required?: boolean }) {
  return <label className="form-field">{label}{required && <span className="required-mark"> *</span>}<select required={required} value={value} onChange={(event) => onChange(event.target.value)}><option value="">Sélectionner</option>{children}</select>{hint && <span className="field-help">{hint}</span>}</label>;
}

function formatDate(value: string) {
  if (!value) return "Non identifié";
  return new Intl.DateTimeFormat("fr-FR").format(new Date(`${value}T12:00:00`));
}

function formatMoney(value: number | null) {
  if (value === null || value === undefined) return "—";
  return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" }).format(Number(value));
}

export default function Home() {
  const [step, setStep] = useState(0);
  const [eligibility, setEligibility] = useState<Eligibility>(initialEligibility);
  const [answers, setAnswers] = useState<Answers>(initialAnswers);
  const [extracted, setExtracted] = useState<RiExtracted>(emptyRi);
  const [user, setUser] = useState<User | null>(null);
  const [dossier, setDossier] = useState<DossierRow | null>(null);
  const [email, setEmail] = useState("");
  const [otp, setOtp] = useState("");
  const [otpSent, setOtpSent] = useState(false);
  const [riFileName, setRiFileName] = useState("");
  const [riConfirmed, setRiConfirmed] = useState(false);
  const [showRiHelp, setShowRiHelp] = useState(false);
  const [insurerSearch, setInsurerSearch] = useState("");
  const [requestCopied, setRequestCopied] = useState(false);
  const [consentData, setConsentData] = useState(false);
  const [consentAccuracy, setConsentAccuracy] = useState(false);
  const [busy, setBusy] = useState(false);
  const [loadingSession, setLoadingSession] = useState(true);
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");
  const [emailDelivery, setEmailDelivery] = useState<"idle" | "sending" | "sent" | "failed">("idle");
  const [callbackForm, setCallbackForm] = useState<CallbackForm>({ firstName: "", lastName: "", phone: "", website: "" });
  const [callbackRequestKey] = useState(() => crypto.randomUUID());
  const [callbackStatus, setCallbackStatus] = useState<"idle" | "sending" | "sent">("idle");
  const [documentsMode, setDocumentsMode] = useState(false);
  const [workspaceMode, setWorkspaceMode] = useState(false);
  const [riReturnMode, setRiReturnMode] = useState(false);
  const [quotesMode, setQuotesMode] = useState(false);
  const [publishedQuotes, setPublishedQuotes] = useState<QuoteRow[]>([]);
  const [quoteSelectionBusy, setQuoteSelectionBusy] = useState<string | null>(null);
  const [subscriptionDocuments, setSubscriptionDocuments] = useState<Partial<Record<SubscriptionDocumentType, SubscriptionDocumentRow>>>({});
  const [uploadingDocument, setUploadingDocument] = useState<SubscriptionDocumentType | null>(null);
  const [documentsDelivery, setDocumentsDelivery] = useState<"idle" | "sending" | "sent" | "failed">("idle");
  const linkVerified = useRef(false);
  const [comparisonPdf, setComparisonPdf] = useState<{file_path:string;original_name:string}|null>(null);

  const updateAnswer = (key: keyof Answers, value: string) => setAnswers((old) => ({ ...old, [key]: value }));
  const updateRi = (key: keyof RiExtracted, value: string) => setExtracted((old) => ({ ...old, [key]: value }));

  const selectedInsurer = insurerGuides.find((insurer) => insurer.id === eligibility.insurerId) || null;
  const filteredInsurers = useMemo(() => {
    const query = insurerSearch.trim().toLocaleLowerCase("fr");
    if (!query) return insurerGuides.slice(0, 20);
    return insurerGuides.filter((insurer) => [insurer.name, insurer.insurer || "", ...insurer.aliases].some((value) => value.toLocaleLowerCase("fr").includes(query))).slice(0, 20);
  }, [insurerSearch]);

  async function loadSubscriptionDocuments(dossierId: string) {
    const { data, error: documentsError } = await supabase.from("auto_subscription_documents").select("*").eq("dossier_id", dossierId);
    if (documentsError) {
      setError("Vos pièces n’ont pas pu être affichées. Réessayez dans quelques instants.");
      return;
    }
    const nextDocuments: Partial<Record<SubscriptionDocumentType, SubscriptionDocumentRow>> = {};
    for (const document of (data || []) as SubscriptionDocumentRow[]) nextDocuments[document.document_type] = document;
    setSubscriptionDocuments(nextDocuments);
  }

  async function loadPublishedQuotes(dossierId: string) {
    setComparisonPdf(null);
    const { data: comparison } = await supabase.from("auto_comparisons").select("file_path,original_name").eq("dossier_id", dossierId).not("published_at", "is", null).maybeSingle();
    setComparisonPdf(comparison);
    const { data, error: quotesError } = await supabase.from("auto_quotes").select("*").eq("dossier_id", dossierId).in("status", ["published", "selected"]).order("position");
    if (quotesError) {
      setError("Vos propositions n’ont pas pu être affichées. Réessayez dans quelques instants.");
      return [];
    }
    const rows = ((data || []) as QuoteRow[]).sort((a,b) => a.annual_premium - b.annual_premium || a.position - b.position);
    setPublishedQuotes(rows);
    return rows;
  }

  async function loadDossier(userId: string, openDocuments = false, openWorkspace = false, openRiReturn = false, openQuotes = false) {
    const targetId = new URLSearchParams(window.location.search).get("dossier");
    let query = supabase.from("auto_dossiers").select("*").eq("user_id", userId);
    if (targetId) query = query.eq("id", targetId);
    else if (openQuotes) query = query.eq("status", "submitted").order("quotes_published_at", { ascending: false, nullsFirst: false });
    else if (openDocuments) query = query.eq("status", "submitted").order("documents_requested_at", { ascending: false, nullsFirst: false });
    const { data, error: queryError } = await query.order("updated_at", { ascending: false }).limit(1).maybeSingle();
    if (queryError) {
      setError("Votre espace est ouvert, mais le dossier n’a pas pu être repris. Réessayez dans quelques instants.");
      setLoadingSession(false); return null;
    }
    if (data) {
      const row = data as DossierRow;
      const storedAnswers = row.answers || initialAnswers;
      const normalizedLicenceCountry = storedAnswers.licenceCountry === "France ou Union européenne" ? "En France - UE" : storedAnswers.licenceCountry;
      const formulaAliases: Record<string, string> = {
        "Responsabilité civile": "Tiers",
        "Essentielle": "Tiers",
        "Médium": "Tiers étendu",
        "Tiers étendu": "Tiers étendu",
        "Tous Risques": "Tous risques",
        "Tous risques": "Tous risques",
      };
      const normalizedFormula = formulaAliases[storedAnswers.desiredFormula] || storedAnswers.desiredFormula;
      setDossier(row);
      setEligibility({ ...initialEligibility, ...(row.eligibility || {}) });
      setAnswers({
        ...initialAnswers,
        ...storedAnswers,
        phone: row.phone || row.answers?.phone || "",
        registration: row.answers?.registration || row.ri_extracted?.registration || "",
        mainDriverName: row.answers?.mainDriverName || row.ri_extracted?.policyholderName || "",
        mainDriverBirthDate: row.answers?.mainDriverBirthDate || row.ri_extracted?.birthDate || "",
        licenceIssueDate: row.answers?.licenceIssueDate || row.ri_extracted?.licenceFirstIssueDate || "",
        licenceCountry: normalizedLicenceCountry,
        desiredFormula: normalizedFormula,
      });
      setExtracted({ ...emptyRi, ...(row.ri_extracted || {}) });
      setRiFileName(row.ri_original_name || "");
      setRiConfirmed(row.ri_confirmed);
      setConsentData(row.consent_data_processing);
      setConsentAccuracy(row.consent_accuracy);
      if (openQuotes) {
        const rows = await loadPublishedQuotes(row.id);
        setStep(12);
        setMessage(rows.length ? "Vos propositions sont disponibles dans votre espace sécurisé." : "Votre étude est toujours en cours. Vous serez averti dès que vos propositions seront disponibles.");
      } else if (openRiReturn && row.status === "waiting_ri") {
        setEligibility((current) => ({ ...current, riStatus: "disponible", riRequested: false }));
        setStep(3);
        setMessage("Votre dossier est rouvert. Déposez maintenant le relevé reçu de votre assureur.");
      } else if (openRiReturn) {
        setStep(row.status === "submitted" ? 10 : Math.min(Math.max(row.current_step, 1), 7));
        setMessage(row.status === "submitted" ? "Votre dossier a déjà été transmis." : "Votre progression a bien été retrouvée.");
      } else if (openDocuments && (row.documents_requested_at || ["quote_selected", "documents_pending", "documents_complete", "ready_for_edi", "sent_to_edi", "signed", "finalized"].includes(row.workflow_status))) {
        await loadSubscriptionDocuments(row.id);
        setStep(9);
        setMessage("Votre espace de dépôt sécurisé est ouvert.");
      } else if (openDocuments) {
        setStep(2);
        setMessage("");
        setError("Les pièces complémentaires seront accessibles après le choix de votre proposition.");
      } else if (openWorkspace) {
        setStep(10);
        setMessage("Votre dossier sécurisé a bien été retrouvé.");
      } else {
        setStep(row.status === "submitted" ? 8 : Math.min(Math.max(row.current_step, 1), 7));
        setMessage(row.status === "submitted" ? "Votre dossier a déjà été transmis." : "Votre progression a été retrouvée.");
      }
      setLoadingSession(false);
      return row;
    }
    if (openDocuments || openWorkspace || openQuotes) {
      setStep(2);
      setError("Aucune demande d’étude automobile n’est associée à cette adresse e-mail.");
    }
    setLoadingSession(false);
    return null;
  }

  useEffect(() => {
    let active = true;
    supabase.auth.getSession().then(({ data }) => {
      if (!active) return;
      const query = new URLSearchParams(window.location.search);
      const wantsDocuments = query.get("pieces") === "1";
      const wantsWorkspace = query.get("espace") === "1";
      const wantsRiReturn = query.get("releve") === "1";
      const wantsQuotes = query.get("devis") === "1";
      setDocumentsMode(wantsDocuments);
      setWorkspaceMode(wantsWorkspace);
      setRiReturnMode(wantsRiReturn);
      setQuotesMode(wantsQuotes);
      if (wantsQuotes || wantsDocuments) {
        setUser(null); setEmail(""); setStep(2); setLoadingSession(false);
        return;
      }
      const sessionUser = data.session?.user || null;
      setUser(sessionUser);
      if (sessionUser?.email) setEmail(sessionUser.email);
      if (sessionUser) void loadDossier(sessionUser.id, wantsDocuments, wantsWorkspace, wantsRiReturn, wantsQuotes);
      else {
        if (wantsDocuments || wantsWorkspace || wantsRiReturn || wantsQuotes) setStep(2);
        else if (query.get("demarrer") === "1") setStep(1);
        setLoadingSession(false);
      }
    });
    const { data: listener } = supabase.auth.onAuthStateChange((_event, session) => {
      if (!active) return;
      const query = new URLSearchParams(window.location.search);
      if ((query.get("devis") === "1" || query.get("pieces") === "1") && !linkVerified.current) return;
      setUser(session?.user || null);
      if (session?.user.email) setEmail(session.user.email);
    });
    return () => { active = false; listener.subscription.unsubscribe(); };
  }, []);

  async function ensureDossier(activeUser = user) {
    if (!activeUser) return null;
    if (dossier) return dossier;
    const { data, error: insertError } = await supabase.from("auto_dossiers").insert({ user_id: activeUser.id, prospect_email: activeUser.email || null, eligibility, current_step: Math.max(step, 1) }).select("*").single();
    if (insertError) throw insertError;
    const row = data as DossierRow; setDossier(row); return row;
  }

  async function saveProgress(targetStep = step) {
    if (!user) return true;
    try {
      const activeDossier = await ensureDossier();
      if (!activeDossier) return false;
      const { error: updateError } = await supabase.from("auto_dossiers").update({
        current_step: Math.min(Math.max(targetStep, 1), 7), phone: answers.phone || null, eligibility,
        ri_issue_date: extracted.documentDate || null, ri_extracted: extracted, ri_confirmed: riConfirmed,
        answers, consent_data_processing: consentData, consent_accuracy: consentAccuracy, updated_at: new Date().toISOString(),
      }).eq("id", activeDossier.id);
      if (updateError) throw updateError;
      setDossier((old) => old ? { ...old, current_step: targetStep, eligibility, ri_extracted: extracted, ri_confirmed: riConfirmed, answers, phone: answers.phone } : old);
      setMessage("Progression enregistrée automatiquement."); return true;
    } catch { setError("L’enregistrement n’a pas abouti. Vérifiez votre connexion avant de continuer."); return false; }
  }

  async function sendOtp() {
    setError(""); setMessage("");
    if (!/^\S+@\S+\.\S+$/.test(email)) { setError("Saisissez une adresse e-mail valide."); return; }
    setBusy(true);
    const { error: authError } = await supabase.auth.signInWithOtp({
      email,
      options: {
        shouldCreateUser: true,
        // If an email template ever contains a confirmation link, it must
        // return to the public app origin rather than Supabase's local default.
        emailRedirectTo: documentsMode
          ? `${window.location.origin}/?pieces=1${new URLSearchParams(window.location.search).get("dossier") ? `&dossier=${encodeURIComponent(new URLSearchParams(window.location.search).get("dossier")!)}` : ""}`
          : quotesMode
            ? `${window.location.origin}/?devis=1${new URLSearchParams(window.location.search).get("dossier") ? `&dossier=${encodeURIComponent(new URLSearchParams(window.location.search).get("dossier")!)}` : ""}`
          : riReturnMode
            ? `${window.location.origin}/?releve=1`
          : workspaceMode
            ? `${window.location.origin}/?espace=1`
            : window.location.origin,
      },
    });
    setBusy(false);
    if (authError) { setError(authError.status === 429 ? "Un code vient déjà d’être envoyé. Patientez une minute avant un nouvel essai." : "Le code n’a pas pu être envoyé. Vérifiez l’adresse puis réessayez."); return; }
    setOtpSent(true); setMessage("Code envoyé. Consultez également vos courriers indésirables.");
  }

  async function verifyOtp() {
    setError("");
    if (otp.length !== OTP_LENGTH) { setError(`Le code doit contenir ${OTP_LENGTH} chiffres.`); return; }
    setBusy(true);
    const { data, error: verifyError } = await supabase.auth.verifyOtp({ email, token: otp, type: "email" });
    if (verifyError || !data.user) { setBusy(false); setError("Ce code est incorrect ou a expiré. Demandez-en un nouveau si nécessaire."); return; }
    linkVerified.current = true;
    setUser(data.user);
    if (documentsMode) {
      const existingDossier = await loadDossier(data.user.id, true);
      if (existingDossier?.status === "submitted") setMessage("Adresse vérifiée. Vous pouvez déposer les pièces demandées par MAGA Assurances.");
      setBusy(false);
      return;
    }
    if (quotesMode) {
      await loadDossier(data.user.id, false, false, false, true);
      setBusy(false);
      return;
    }
    if (riReturnMode) {
      const existingDossier = await loadDossier(data.user.id, false, false, true);
      if (existingDossier?.status === "waiting_ri") setMessage("Adresse vérifiée. Déposez maintenant votre relevé d’informations.");
      setBusy(false);
      return;
    }
    if (workspaceMode) {
      const existingDossier = await loadDossier(data.user.id, false, true);
      if (existingDossier) setMessage("Adresse vérifiée. Votre dossier sécurisé est ouvert.");
      setBusy(false);
      return;
    }
    try {
      const activeDossier = await ensureDossier(data.user);
      if (activeDossier) await supabase.from("auto_dossiers").update({ eligibility, current_step: 3, updated_at: new Date().toISOString() }).eq("id", activeDossier.id);
      setMessage("Adresse vérifiée. Votre dossier sécurisé est ouvert.");
    } catch { setError("Votre adresse est vérifiée, mais le dossier n’a pas pu être créé."); }
    setBusy(false);
  }

  async function submitCallbackRequest() {
    setError(""); setMessage("");
    const phoneDigits = callbackForm.phone.replace(/\D/g, "");
    if (callbackForm.firstName.trim().length < 2 || callbackForm.lastName.trim().length < 2 || phoneDigits.length < 10) {
      setError("Renseignez votre nom, votre prénom et un numéro de téléphone valide.");
      return;
    }
    setCallbackStatus("sending");
    const { error: callbackError } = await supabase.functions.invoke("notify-auto-callback", {
      body: { ...callbackForm, requestKey: callbackRequestKey },
    });
    if (callbackError) {
      setCallbackStatus("idle");
      setError("Votre demande de rappel n’a pas pu être transmise. Réessayez dans quelques instants.");
      return;
    }
    setCallbackStatus("sent");
    setMessage("Votre demande de rappel a bien été transmise à MAGA Assurances.");
  }

  async function handleRiFile(event: ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0]; if (!file || !user) return;
    setError(""); setMessage("");
    if (!["application/pdf", "image/jpeg", "image/png"].includes(file.type) || file.size > 10 * 1024 * 1024) {
      setError("Choisissez un PDF, JPG ou PNG de 10 Mo maximum."); event.target.value = ""; return;
    }
    setBusy(true);
    let parsed = { ...emptyRi }; let needsReview = false;
    try { const result = await extractRiFromFile(file); parsed = result.extracted; needsReview = !result.text; } catch { needsReview = true; }
    try {
      const activeDossier = await ensureDossier(); if (!activeDossier) throw new Error("No dossier");
      const safeName = file.name.normalize("NFKD").replace(/[^a-zA-Z0-9._-]/g, "-").slice(-100);
      const path = `${user.id}/${activeDossier.id}/${Date.now()}-${safeName}`;
      const previousPath = activeDossier.ri_file_path;
      const { error: uploadError } = await supabase.storage.from("ri-documents").upload(path, file, { contentType: file.type, upsert: false });
      if (uploadError) throw uploadError;
      const issueDate = parsed.documentDate || "";
      const nextEligibility = { ...eligibility, riStatus: "disponible", riRequested: false };
      const nextAnswers: Answers = {
        ...answers,
        registration: parsed.registration || "",
        registrationMatchesCard: "",
        mainDriverName: parsed.policyholderName || "",
        mainDriverBirthDate: parsed.birthDate || "",
        licenceIssueDate: parsed.licenceFirstIssueDate || "",
      };
      const { error: updateError } = await supabase.from("auto_dossiers").update({
        status: needsReview ? "needs_review" : "ri_uploaded", current_step: 4, ri_file_path: path,
        ri_original_name: file.name, ri_mime_type: file.type, ri_file_size: file.size,
        ri_issue_date: issueDate || null, ri_extracted: parsed, ri_confirmed: false,
        eligibility: nextEligibility, answers: nextAnswers, updated_at: new Date().toISOString(),
      }).eq("id", activeDossier.id);
      if (updateError) {
        await supabase.storage.from("ri-documents").remove([path]);
        throw updateError;
      }
      if (previousPath && previousPath !== path) await supabase.storage.from("ri-documents").remove([previousPath]);
      setDossier((old) => old ? { ...old, status: needsReview ? "needs_review" : "ri_uploaded", ri_file_path: path, ri_original_name: file.name, ri_mime_type: file.type, ri_file_size: file.size, ri_issue_date: issueDate, ri_extracted: parsed, ri_confirmed: false, eligibility: nextEligibility, answers: nextAnswers } : old);
      setEligibility(nextEligibility);
      setExtracted(parsed); setRiConfirmed(false); setRiFileName(file.name);
      setAnswers(nextAnswers);
      setMessage(needsReview ? "Nouveau relevé enregistré. Les anciennes données du RI ont été effacées ; complétez les informations qui n’ont pas pu être lues." : "Nouveau relevé enregistré et analysé. Les anciennes données ont été remplacées par celles de ce document.");
    } catch { setError("Le relevé n’a pas pu être enregistré. Aucun document n’a été envoyé par e-mail ; réessayez."); }
    event.target.value = "";
    setBusy(false);
  }

  async function handleSubscriptionFile(documentType: SubscriptionDocumentType, event: ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file || !user || !dossier || !["quote_selected", "documents_pending", "documents_complete", "ready_for_edi", "sent_to_edi", "signed", "finalized"].includes(dossier.workflow_status)) return;
    setError(""); setMessage("");
    if (!["application/pdf", "image/jpeg", "image/png"].includes(file.type) || file.size > 10 * 1024 * 1024) {
      setError("Choisissez un PDF, JPG ou PNG de 10 Mo maximum.");
      event.target.value = "";
      return;
    }

    setUploadingDocument(documentType);
    const previousDocument = subscriptionDocuments[documentType];
    const safeName = file.name.normalize("NFKD").replace(/[^a-zA-Z0-9._-]/g, "-").slice(-100);
    const path = `${user.id}/${dossier.id}/${documentType}/${Date.now()}-${safeName}`;

    try {
      const { error: uploadError } = await supabase.storage.from("subscription-documents").upload(path, file, { contentType: file.type, upsert: false });
      if (uploadError) throw uploadError;

      const { data, error: metadataError } = await supabase.from("auto_subscription_documents").upsert({
        dossier_id: dossier.id,
        user_id: user.id,
        document_type: documentType,
        file_path: path,
        original_name: file.name,
        mime_type: file.type,
        file_size: file.size,
        uploaded_at: new Date().toISOString(),
        updated_at: new Date().toISOString(),
      }, { onConflict: "dossier_id,document_type" }).select("*").single();

      if (metadataError || !data) {
        await supabase.storage.from("subscription-documents").remove([path]);
        throw metadataError || new Error("Missing metadata");
      }

      if (previousDocument?.file_path && previousDocument.file_path !== path) {
        await supabase.storage.from("subscription-documents").remove([previousDocument.file_path]);
      }

      const nextDocuments = { ...subscriptionDocuments, [documentType]: data as SubscriptionDocumentRow };
      setSubscriptionDocuments(nextDocuments);
      setDocumentsDelivery("idle");
      const isComplete = subscriptionDocumentSlots.every((slot) => !!nextDocuments[slot.type]);
      setMessage(isComplete ? "Toutes les pièces demandées sont déposées. MAGA Assurances peut finaliser votre dossier de souscription." : "Pièce enregistrée dans votre espace sécurisé.");
    } catch {
      setError("Cette pièce n’a pas pu être enregistrée. Vérifiez le fichier puis réessayez.");
    }
    event.target.value = "";
    setUploadingDocument(null);
  }

  async function sendSubscriptionDocuments() {
    if (!dossier?.id || !user || Object.values(subscriptionDocuments).filter(Boolean).length === 0) return;
    setDocumentsDelivery("sending"); setError(""); setMessage("");
    const { data, error: functionError } = await supabase.functions.invoke("notify-auto-subscription-documents", {
      body: { dossierId: dossier.id },
    });
    if (functionError) {
      setDocumentsDelivery("failed");
      setError("Vos pièces restent enregistrées, mais MAGA Assurances n’a pas encore pu être averti. Réessayez avec le bouton Envoyer.");
      return;
    }
    setDocumentsDelivery("sent");
    setMessage(data?.complete
      ? "Votre dossier documentaire complet a bien été signalé à MAGA Assurances."
      : "Les pièces déjà déposées ont été signalées à MAGA Assurances. Un e-mail vous indique les pièces encore attendues et contient le lien pour revenir ici.");
    setStep(11);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  const riIsRecent = isRiRecent(extracted.documentDate);
  const uploadedDocumentCount = subscriptionDocumentSlots.filter((slot) => !!subscriptionDocuments[slot.type]).length;
  const uploadedAnyDocument = Object.values(subscriptionDocuments).filter(Boolean).length > 0;
  const subscriptionDocumentsComplete = uploadedDocumentCount === subscriptionDocumentSlots.length;
  const canContinue = useMemo(() => {
    if (step === 1) return eligibility.insured === "oui" && ["disponible", "demander"].includes(eligibility.riStatus);
    if (step === 2) return !!user;
    if (step === 3) return !!riFileName && riIsRecent;
    if (step === 4) return /^[A-Z]{2}-?\d{3}-?[A-Z]{2}$/.test(answers.registration.toUpperCase()) && answers.registrationMatchesCard === "oui" && !!answers.cardIssueDate && !!answers.registeredHolder && (answers.registeredHolder === "oui" || !!answers.ownerRelationship) && !!answers.acquisition;
    if (step === 5) {
      const frenchOrEuLicence = answers.licenceCountry === "En France - UE";
      const accompaniedDrivingComplete = !frenchOrEuLicence || (!!answers.accompaniedDriving && (answers.accompaniedDriving === "non" || !!answers.accompaniedDrivingType));
      return !!answers.mainDriverName && !!answers.mainDriverBirthDate && answers.phone.replace(/\D/g, "").length >= 10 && !!answers.maritalStatus && !!answers.licenceCountry && !!answers.licenceIssueDate && accompaniedDrivingComplete && !!answers.parkingType && /^\d{5}$/.test(answers.parkingPostalCode) && (answers.parkingType !== "rue" || (!!answers.housingType && !!answers.housingTenure)) && (answers.parkingType !== "autre" || (!!answers.parkingCollective && !!answers.parkingClosed && !!answers.parkingCovered)) && !!answers.profession && (answers.profession !== "Autre" || !!answers.professionOther) && !!answers.usage && !!answers.mileage && !!answers.householdDrivers && !!answers.householdVehicles && (answers.householdDrivers === "1" || !!answers.householdYoungLicences);
    }
    if (step === 6) return answers.aggravations.length > 0 && !!answers.protectionPriority && !!answers.desiredFormula;
    if (step === 7) return consentData && consentAccuracy;
    return true;
  }, [answers, consentAccuracy, consentData, eligibility, extracted, riConfirmed, riFileName, riIsRecent, step, user]);

  async function next() {
    setError(""); if (!canContinue) return;
    const target = Math.min(step + 1, 7);
    if (user && !(await saveProgress(target))) return;
    setStep(target); window.scrollTo({ top: 0, behavior: "smooth" });
  }

  async function submitDossier() {
    if (!user || !canContinue) return; setBusy(true); setError("");
    try {
      const activeDossier = await ensureDossier(); if (!activeDossier) throw new Error("No dossier");
      const { error: submitError } = await supabase.from("auto_dossiers").update({
        status: "submitted", phone: answers.phone, eligibility, ri_issue_date: extracted.documentDate,
        ri_extracted: extracted, ri_confirmed: true, answers, consent_data_processing: true,
        consent_accuracy: true, prospect_email: user.email || null,
        workflow_status: dossier?.workflow_status && dossier.workflow_status !== "draft" ? dossier.workflow_status : "new_request",
        submitted_at: new Date().toISOString(), updated_at: new Date().toISOString(),
      }).eq("id", activeDossier.id);
      if (submitError) throw submitError;
      setDossier((old) => old ? { ...old, status: "submitted" } : old);
      setStep(8); setMessage("");
      await sendCompletionEmails(activeDossier.id);
    } catch { setError("La transmission n’a pas abouti. Votre progression reste enregistrée ; réessayez."); }
    setBusy(false);
  }

  async function sendCompletionEmails(dossierId = dossier?.id) {
    if (!dossierId || !user) return false;
    setEmailDelivery("sending"); setError("");
    const { error: functionError } = await supabase.functions.invoke("notify-auto-dossier", {
      body: { dossierId },
    });
    if (functionError) {
      setEmailDelivery("failed");
      return false;
    }
    setEmailDelivery("sent");
    return true;
  }

  async function markRiRequested() {
    if (!user || !selectedInsurer) return;
    setBusy(true); setError("");
    let dossierSaved = false;
    try {
      const nextEligibility = { ...eligibility, insurerName: selectedInsurer.name, riRequested: true };
      const activeDossier = await ensureDossier();
      if (!activeDossier) throw new Error("No dossier");
      const { error: updateError } = await supabase.from("auto_dossiers").update({
        status: "waiting_ri", current_step: 3, eligibility: nextEligibility, updated_at: new Date().toISOString(),
      }).eq("id", activeDossier.id);
      if (updateError) throw updateError;
      dossierSaved = true;
      const { error: notificationError } = await supabase.functions.invoke("notify-auto-dossier", {
        body: { dossierId: activeDossier.id, event: "ri_waiting" },
      });
      if (notificationError) throw notificationError;
      await signOut();
      setMessage("Votre dossier est conservé. Nous vous avons envoyé un e-mail pour le reprendre dès réception de votre relevé d’informations.");
      window.scrollTo({ top: 0, behavior: "smooth" });
    } catch {
      setError(dossierSaved
        ? "Votre dossier est bien enregistré, mais l’e-mail de reprise n’a pas pu être envoyé. Cliquez à nouveau sur le bouton avant de quitter la page."
        : "Votre demande n’a pas pu être enregistrée. Réessayez avant de quitter la page.");
    }
    setBusy(false);
  }

  function openReceivedRiUpload() {
    setEligibility((old) => ({ ...old, riStatus: "disponible", riRequested: false }));
    setMessage("Votre dossier est rouvert. Déposez maintenant le relevé reçu de votre assureur.");
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  async function signOut() {
    await supabase.auth.signOut();
    setUser(null); setDossier(null); setEligibility(initialEligibility); setAnswers(initialAnswers); setExtracted(emptyRi); setRiFileName(""); setRiConfirmed(false); setConsentData(false); setConsentAccuracy(false); setSubscriptionDocuments({}); setPublishedQuotes([]); setDocumentsMode(false); setWorkspaceMode(false); setRiReturnMode(false); setQuotesMode(false); setStep(0); setMessage(""); setError("");
    window.history.replaceState({}, "", window.location.pathname);
  }

  function openDossierForEditing() {
    setDocumentsMode(false);
    setWorkspaceMode(false);
    window.history.replaceState({}, "", window.location.pathname);
    setMessage("Vous pouvez corriger vos déclarations ou remplacer votre relevé. Validez de nouveau le dossier pour transmettre les modifications à MAGA Assurances.");
    setStep(3);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  async function openSubscriptionDocuments() {
    if (!dossier || (!dossier.documents_requested_at && !["quote_selected", "documents_pending", "documents_complete", "ready_for_edi", "sent_to_edi", "signed", "finalized"].includes(dossier.workflow_status))) return;
    setWorkspaceMode(false);
    setDocumentsMode(true);
    window.history.replaceState({}, "", `${window.location.pathname}?pieces=1&dossier=${dossier.id}`);
    await loadSubscriptionDocuments(dossier.id);
    setMessage("Votre espace de dépôt sécurisé est ouvert.");
    setStep(9);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  async function openQuotePdf(quote: Pick<QuoteRow, "file_path">) {
    const { data, error: urlError } = await supabase.storage.from("auto-quotes").createSignedUrl(quote.file_path, 120);
    if (urlError || !data?.signedUrl) { setError("Le devis n’a pas pu être ouvert."); return; }
    window.open(data.signedUrl, "_blank", "noopener,noreferrer");
  }

  async function selectQuote(quote: QuoteRow) {
    if (!dossier || quote.status === "selected") return;
    setQuoteSelectionBusy(quote.id); setError(""); setMessage("");
    const { error: selectError } = await supabase.rpc("select_auto_quote", { p_quote_id: quote.id });
    if (selectError) { setError("Votre choix n’a pas pu être enregistré. Réessayez dans quelques instants."); setQuoteSelectionBusy(null); return; }
    await supabase.functions.invoke("notify-auto-quotes", { body: { action: "selected", dossierId: dossier.id, quoteId: quote.id } });
    const updatedDossier = { ...dossier, selected_quote_id: quote.id, workflow_status: "quote_selected" };
    setDossier(updatedDossier); await loadPublishedQuotes(dossier.id);
    setMessage("Votre choix est enregistré. Vous pouvez maintenant déposer les pièces nécessaires à la souscription.");
    setQuoteSelectionBusy(null); window.scrollTo({ top: 0, behavior: "smooth" });
  }

  function returnToWorkspace() {
    setDocumentsMode(false);
    setWorkspaceMode(true);
    setDocumentsDelivery("idle");
    window.history.replaceState({}, "", `${window.location.pathname}?espace=1`);
    setMessage("Votre dossier sécurisé reste accessible.");
    setStep(10);
    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  if (loadingSession) return <main className="loading"><img src="/maga-logo-official.png" width="502" height="304" alt="MAGA Assurances" /><div className="loader" /><p>Ouverture de votre espace sécurisé…</p></main>;

  return <main>
    <header className="topbar">
      <button className="brand" type="button" onClick={() => setStep(0)}><img className="brand-logo" src="/maga-logo-official.png" width="502" height="304" alt="MAGA Assurances" /></button>
      <div className="header-actions">{user?.email && <span className="session-email">{user.email}</span>}{step > 0 && <button type="button" className="signout" onClick={signOut}>Quitter</button>}<div className="secure"><span>●</span> Accès sécurisé</div></div>
    </header>
    {!documentsMode && !workspaceMode && !quotesMode && step > 0 && step < 8 && <div className="progress-wrap" aria-label={`Étape ${Math.min(step, 7)} sur 7`}><div className="progress"><span style={{ width: `${Math.min(step, 7) / 7 * 100}%` }} /></div><p>Étape {step} sur 7 · {steps[step]}</p></div>}
    {(message || error) && <div className={`flash ${error ? "flash-error" : ""}`} role={error ? "alert" : "status"}>{error || message}</div>}

    <section className="shell">
      {step === 0 && <div className="hero landing-v3">
        <section className="auto-hero">
          <div className="auto-hero-copy">
            <p className="auto-kicker">ASSURANCE AUTOMOBILE · CONDUCTEURS DÉJÀ ASSURÉS</p>
            <h1>Renégociez votre assurance automobile.</h1>
            <p className="auto-hero-lead">Votre contrat a évolué. Votre tarif aussi. À partir de votre relevé d’informations, MAGA Assurances recherche jusqu’à trois propositions adaptées à votre profil et à votre véhicule.</p>
            <button className="auto-cta" onClick={next}>Je fais étudier mon contrat <span aria-hidden="true">→</span></button>
            <div className="auto-hero-points" aria-label="Les engagements de l’étude"><span>Gratuit</span><span>Sans engagement</span><span>Données sécurisées</span></div>
          </div>
          <figure className="auto-hero-photo">
            <img src="/photo-maga-2.webp" width="1600" height="1019" alt="Conductrice souriante près de son véhicule" />
            <figcaption><strong>Jusqu’à 3</strong><span>propositions comparées</span></figcaption>
          </figure>
        </section>

        <section className="market-proof" aria-label="Pourquoi renégocier son assurance automobile">
          <div className="market-proof-title"><p className="auto-kicker">POURQUOI MAINTENANT ?</p><h2>Le bon contrat d’hier n’est pas forcément le bon contrat d’aujourd’hui.</h2></div>
          <div className="market-stat"><strong>+6,5 %</strong><p>de hausse de la prime moyenne automobile en 2025 par rapport à 2024.</p><a href="https://www.franceassureurs.fr/nos-chiffres-cles/assurance-de-dommages-et-responsabilite/marche-assurance-automobile-particuliers-2025/" target="_blank" rel="noreferrer">Source : France Assureurs</a></div>
          <div className="market-stat market-stat-example"><span>EXEMPLE RÉEL</span><strong>−22 %</strong><p>soit 288 € économisés par an pour une Tesla Model Y assurée tous risques.</p><small>Contrat souscrit en juillet 2026 · bonus 50 %. Les résultats varient selon le profil et les garanties.</small></div>
        </section>

        <section className="ri-feature">
          <div className="ri-paper" aria-hidden="true"><span>RI</span><i>Relevé d’informations</i><b>✓</b></div>
          <div className="ri-feature-copy"><p className="auto-kicker">UN POINT DE DÉPART FIABLE</p><h2>Votre relevé d’informations fait déjà une grande partie du travail.</h2><p>Il reprend notamment votre véhicule, votre bonus-malus, votre antériorité et vos éventuels sinistres. Nous l’utilisons pour limiter les questions et préparer une étude basée sur votre situation réelle.</p><button className="auto-link" type="button" onClick={next}>Commencer avec mon relevé <span>→</span></button></div>
        </section>

        <section className="auto-process" aria-labelledby="process-title">
          <div className="auto-section-heading"><p className="auto-kicker">SIMPLE, MAIS PAS AUTOMATIQUE</p><h2 id="process-title">Une étude réalisée par un courtier, en trois étapes.</h2></div>
          <ol>
            <li><span>01</span><div><h3>Vous déposez votre relevé</h3><p>Dans votre espace sécurisé, au format PDF ou en photo.</p></div></li>
            <li><span>02</span><div><h3>Vous complétez l’essentiel</h3><p>Nous demandons uniquement les informations absentes du document.</p></div></li>
            <li><span>03</span><div><h3>Vous comparez les propositions</h3><p>Tarifs, garanties et franchises sont présentés clairement.</p></div></li>
          </ol>
        </section>

        <section className="maga-benefits" aria-labelledby="benefits-title">
          <div className="maga-benefits-intro"><p className="auto-kicker">VOS AVANTAGES AVEC MAGA ASSURANCES</p><h2 id="benefits-title">Un service digital, avec quelqu’un derrière.</h2><p>Vous avancez en ligne, mais votre demande est étudiée et suivie par un professionnel de l’assurance.</p><figure className="benefits-photo"><img src="/photo-maga-1.webp" width="1600" height="1067" alt="Couple souriant lors d’un trajet automobile" /></figure></div>
          <div className="maga-benefits-list">
            <article><span>01</span><div><h3>Des propositions réellement comparables</h3><p>Jusqu’à trois solutions adaptées à votre profil, avec les garanties et franchises visibles.</p></div></article>
            <article><span>02</span><div><h3>Vos documents à portée de main</h3><p>Après souscription, retrouvez vos contrats et attestations dans votre espace personnel.</p></div></article>
            <article><span>03</span><div><h3>La résiliation prise en charge</h3><p>Si vous retenez une proposition, MAGA Assurances organise la mise en place du contrat et la résiliation de l’ancien.*</p></div></article>
          </div>
        </section>

        <section className="support-band">
          <div className="support-copy"><p className="auto-kicker">APRÈS LA SOUSCRIPTION</p><h2>Une fois assuré, nous restons là.</h2><div className="support-items"><p><strong>Une question ?</strong><span>Contactez directement notre équipe.</span></p><p><strong>Besoin d’une attestation ?</strong><span>Téléchargez-la depuis votre espace personnel.</span></p><p><strong>Un changement à déclarer ?</strong><span>Nous vous accompagnons dans la mise à jour du contrat.</span></p></div></div>
          <figure className="support-photo"><img src="/photo-maga-3.webp" width="1600" height="1067" alt="Couple en voyage près de son véhicule" /></figure>
        </section>

        <section className="trust-and-faq">
          <div className="trust-panel"><p className="auto-kicker">VOS INFORMATIONS</p><h2>Vous savez à qui vous les confiez.</h2><p>MAGA Assurances est un courtier en assurances inscrit à l’ORIAS sous le n° 23 0049 53 et exerçant sous le contrôle de l’ACPR. Vos données sont hébergées dans l’Union européenne, utilisées uniquement pour établir votre étude et ne sont jamais revendues.</p><div className="trust-signature"><span aria-hidden="true">✓</span><p><strong>Accès sécurisé par code</strong><small>Votre relevé reste dans votre dossier privé.</small></p></div></div>
          <div className="faq-panel"><p className="auto-kicker">QUESTIONS FRÉQUENTES</p><h2>Avant de commencer</h2><details><summary>L’étude est-elle vraiment gratuite ?</summary><p>Oui. La demande d’étude et la comparaison sont gratuites et sans engagement.</p></details><details><summary>Pourquoi faut-il un relevé de moins de trois mois ?</summary><p>Un relevé récent permet d’étudier votre situation d’assurance actuelle et d’éviter une proposition construite sur des informations dépassées.</p></details><details><summary>Dois-je connaître ma cotisation actuelle ?</summary><p>Non. Nous recherchons une proposition à partir de votre profil, des garanties et des franchises, sans nous aligner sur votre tarif actuel.</p></details><details><summary>Que se passe-t-il si une proposition me convient ?</summary><p>Vous restez libre de l’accepter. MAGA Assurances vous accompagne ensuite pour la souscription et, lorsque les conditions le permettent, la résiliation de votre ancien contrat.</p></details></div>
        </section>

        <section className="auto-final-cta">
          <div><p className="auto-kicker">PRÊT À VÉRIFIER VOTRE CONTRAT ?</p><h2>Votre relevé d’informations suffit pour commencer.</h2><p>Quelques minutes de votre côté. Une véritable étude du nôtre.</p></div>
          <button className="auto-cta auto-cta-light" onClick={next}>Démarrer mon étude <span aria-hidden="true">→</span></button>
        </section>
      </div>}

      {step === 1 && <div className="card eligibility-card"><div className="step-topline"><span className="step-bubble">1</span><div className="kicker">Vérifions que ce parcours vous correspond</div></div><h1>Vous êtes déjà assuré(e) ?</h1><p className="intro">Votre contrat automobile peut peut-être être mieux adapté ou moins cher. Répondez à deux questions pour commencer votre étude personnalisée.</p>
        <div className="eligibility-benefits" aria-label="Les avantages de l’étude"><span>✓ Étude gratuite</span><span>✓ Jusqu’à 3 propositions</span><span>✓ Sans engagement</span></div>
        <fieldset><legend>Êtes-vous actuellement assuré(e) comme conducteur principal ?</legend><div className="choices two"><Choice value="oui" current={eligibility.insured} onClick={() => setEligibility((old) => ({ ...old, insured: "oui", riStatus: old.riStatus === "retrouver" ? "" : old.riStatus }))}>Oui</Choice><Choice value="non" current={eligibility.insured} onClick={() => setEligibility((old) => ({ ...old, insured: "non" }))}>Non</Choice></div></fieldset>
        {eligibility.insured === "non" && <section className="callback-card"><div><b>Nous pouvons tout de même vous accompagner.</b><p>Cette première version du parcours en ligne est réservée aux conducteurs ayant déjà une antériorité d’assurance automobile. Laissez-nous vos coordonnées : un conseiller vous rappellera pour étudier votre situation.</p></div>{callbackStatus === "sent" ? <div className="callback-success"><span>✓</span><div><b>Votre demande est transmise.</b><p>Un conseiller MAGA Assurances vous rappellera.</p></div></div> : <><div className="callback-grid"><label>Prénom<span className="required-mark"> *</span><input autoComplete="given-name" value={callbackForm.firstName} onChange={(event) => setCallbackForm((old) => ({ ...old, firstName: event.target.value }))} /></label><label>Nom<span className="required-mark"> *</span><input autoComplete="family-name" value={callbackForm.lastName} onChange={(event) => setCallbackForm((old) => ({ ...old, lastName: event.target.value }))} /></label><label>Téléphone<span className="required-mark"> *</span><input type="tel" autoComplete="tel" placeholder="06 12 34 56 78" value={callbackForm.phone} onChange={(event) => setCallbackForm((old) => ({ ...old, phone: event.target.value }))} /></label><label className="callback-honeypot" aria-hidden="true">Votre site<input tabIndex={-1} autoComplete="off" value={callbackForm.website} onChange={(event) => setCallbackForm((old) => ({ ...old, website: event.target.value }))} /></label></div><button className="primary callback-submit" type="button" disabled={callbackStatus === "sending"} onClick={submitCallbackRequest}>{callbackStatus === "sending" ? "Transmission…" : "Je souhaite être rappelé"}<span>→</span></button><small className="callback-consent">En demandant à être rappelé, vous autorisez MAGA Assurances à utiliser ces coordonnées uniquement pour vous recontacter au sujet de votre assurance automobile.</small></>}
        </section>}
        {eligibility.insured === "oui" && <fieldset><legend>Avez-vous un relevé d’informations de moins de 3 mois ?</legend><button className="help-link" type="button" onClick={() => setShowRiHelp(!showRiHelp)}>ⓘ À quoi sert ce document ?</button>{showRiHelp && <div className="notice"><b>Votre relevé d’informations nous évite de vous faire tout ressaisir.</b><br />Il indique notamment votre identité, votre assureur, votre véhicule, votre bonus-malus, vos sinistres, votre antériorité et les conducteurs déclarés.</div>}<div className="choices two"><Choice value="disponible" current={eligibility.riStatus} onClick={() => setEligibility((old) => ({ ...old, riStatus: "disponible", insurerId: "", insurerName: "", riRequested: false }))}>Oui, je l’ai</Choice><Choice value="demander" current={eligibility.riStatus} onClick={() => setEligibility((old) => ({ ...old, riStatus: "demander", riRequested: false }))}>Je dois le demander</Choice></div><p className="ri-choice-helper">Vous ne l’avez pas encore ? Nous vous indiquons comment le demander à votre assureur.</p></fieldset>}
      </div>}

      {step === 2 && <div className="card auth-card"><div className="step-topline"><span className="step-bubble">{documentsMode || workspaceMode || riReturnMode || quotesMode ? "🔒" : "2"}</span><div className="kicker">{documentsMode || workspaceMode || riReturnMode || quotesMode ? "Retour dans votre espace sécurisé" : "Votre espace personnel"}</div></div><h1>{documentsMode ? "Déposez les pièces de votre souscription" : quotesMode ? "Accédez à vos propositions" : riReturnMode ? "Déposez votre relevé d’informations" : workspaceMode ? "Accédez à votre dossier" : "Protégeons votre parcours"}</h1>{documentsMode ? <p className="intro">Identifiez-vous avec la même adresse e-mail que lors de votre demande d’étude. Vous pourrez ensuite charger les documents demandés par MAGA Assurances.</p> : quotesMode ? <p className="intro">Identifiez-vous avec la même adresse e-mail que lors de votre demande. Vous pourrez consulter les propositions préparées pour vous et enregistrer votre choix.</p> : riReturnMode ? <p className="intro">Identifiez-vous avec la même adresse e-mail que lors de votre première visite. Après validation du code, vous accéderez directement au dépôt de votre relevé.</p> : workspaceMode ? <p className="intro">Identifiez-vous avec la même adresse e-mail pour retrouver votre demande, corriger vos déclarations, remplacer votre relevé d’informations ou déposer les pièces demandées.</p> : <div className="intro auth-intro"><p>Pour étudier votre dossier, MAGA Assurances collecte vos coordonnées et les informations nécessaires à l’étude de votre assurance automobile.</p><p>Nous vous demanderons donc votre relevé d’informations et, si vous acceptez ensuite notre proposition, d’autres documents tels que votre permis de conduire, votre carte d’identité et la carte grise. Ils devront être déposés uniquement dans votre espace personnel sécurisé.</p><p>Aucun document officiel n’est transmis par e-mail. Un code reçu par e-mail protège l’accès. Votre adresse e-mail vous permettra également de revenir à tout moment dans votre espace personnel.</p></div>}
        {!user ? <><label>Adresse e-mail<input type="email" autoComplete="email" value={email} onChange={(event) => setEmail(event.target.value)} placeholder="vous@exemple.fr" /></label><button className="secondary wide" type="button" disabled={busy} onClick={sendOtp}>{busy ? "Envoi en cours…" : otpSent ? "Renvoyer un code" : "Recevoir mon code"}</button>{otpSent && <div className="otp-zone"><label>Code à huit chiffres<input className="otp" inputMode="numeric" autoComplete="one-time-code" value={otp} onChange={(event) => setOtp(event.target.value.replace(/\D/g, "").slice(0, OTP_LENGTH))} placeholder="00000000" /></label><button className="primary" type="button" disabled={busy || otp.length !== OTP_LENGTH} onClick={verifyOtp}>Vérifier le code</button></div>}</> : <div className="verified-box"><span>✓</span><div><b>Adresse e-mail vérifiée</b><p>{user.email}</p></div></div>}
        <div className="security-points"><span>🔒 Documents privés</span><span>↻ Accès avec votre code</span><span>✉️ Aucune pièce jointe par e-mail</span></div>
      </div>}

      {step === 3 && <div className={`card ${eligibility.riStatus === "disponible" ? "" : "card-wide"}`}><div className="step-topline"><span className="step-bubble">3</span><div className="kicker">Le point de départ de votre étude</div></div><h1>{eligibility.riStatus === "disponible" ? "Déposez votre relevé d’informations" : "Obtenez votre relevé d’information"}</h1>
        {eligibility.riStatus === "disponible" ? <><p className="intro">Ajoutez le document complet. Nous en extrayons les informations utiles pour éviter de vous les redemander.</p><label className={`upload ${busy ? "upload-busy" : ""}`}><span className="upload-icon">⇧</span><b>{busy ? "Analyse et enregistrement en cours…" : riFileName ? "Remplacer mon relevé" : "Choisir mon relevé"}</b><small>PDF, JPG ou PNG · 10 Mo maximum · toutes les pages</small><input type="file" accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" disabled={busy} onChange={handleRiFile} /></label>{riFileName && <div className="file-ok">✓ {riFileName}</div>}{riFileName && <label>Date d’émission identifiée sur le relevé<input type="date" value={extracted.documentDate} onChange={(event) => updateRi("documentDate", event.target.value)} /><span className={`date-status ${riIsRecent ? "valid" : "invalid"}`}>{riIsRecent ? "✓ Relevé valable : moins de 3 mois" : "Ce relevé a plus de 3 mois ou sa date doit être corrigée."}</span></label>}</> : eligibility.riRequested ? <section className="ri-waiting-screen" aria-live="polite"><div className="ri-waiting-icon">✓</div><div className="kicker">Demande enregistrée</div><h2>Votre dossier vous attend.</h2><p>Vous avez indiqué avoir demandé votre relevé d’informations à <strong>{eligibility.insurerName || selectedInsurer?.name || "votre assureur"}</strong>. Vous pouvez maintenant quitter cet espace en toute sécurité.</p><div className="ri-waiting-steps"><span><b>1</b>Votre progression est conservée.</span><span><b>2</b>À réception du relevé, revenez avec la même adresse e-mail.</span><span><b>3</b>Un nouveau code vous permettra de reprendre le dossier.</span></div>{error && <div className="button-error" role="alert">{error}</div>}<div className="ri-waiting-actions"><button className="primary" type="button" disabled={busy || !selectedInsurer} onClick={markRiRequested}>{busy ? "Envoi du lien…" : "Recevoir mon lien de reprise et quitter"}</button><button className="secondary" type="button" onClick={openReceivedRiUpload}>J’ai reçu mon relevé — le déposer</button></div></section> : <div className="insurer-assistance">
          <p className="intro">Indiquez votre assureur actuel. Nous vous donnons la démarche la plus simple pour demander votre relevé d’information.</p>
          <div className="notice ri-guide"><b>Votre dossier reste ouvert pendant que vous attendez le relevé d’information :</b><ol><li>Choisissez votre banque ou votre assureur.</li><li>Suivez la procédure et envoyez la demande proposée.</li><li>Reconnectez-vous à votre espace personnel avec la même adresse e-mail dès réception du document.</li></ol></div>

          <section className="insurer-picker" aria-labelledby="insurer-picker-title">
            <label id="insurer-picker-title" htmlFor="insurer-search">Auprès de quelle compagnie êtes-vous assuré(e) ?</label>
            <div className="insurer-search-wrap"><span aria-hidden="true">⌕</span><input id="insurer-search" type="search" value={insurerSearch} onChange={(event) => setInsurerSearch(event.target.value)} placeholder="Ex. Direct Assurance, Pacifica, La Banque Postale…" autoComplete="off" /></div>
            <div className="insurer-results" role="list" aria-label="Compagnies proposées">
              {filteredInsurers.map((insurer) => <button key={insurer.id} role="listitem" type="button" className={`${insurer.logoUrl ? "has-logo" : ""} ${eligibility.insurerId === insurer.id ? "selected" : ""}`.trim()} onClick={() => { setEligibility((old) => ({ ...old, insurerId: insurer.id, insurerName: insurer.name, riRequested: false })); setRequestCopied(false); }}>{insurer.logoUrl && <img src={insurer.logoUrl} alt="" loading="lazy" decoding="async" />}<span className="insurer-label"><b>{insurer.name}</b>{insurer.insurer && <small>Contrat assuré par {insurer.insurer}</small>}</span></button>)}
            </div>
            <p className="insurer-trademark-note">Les marques affichées servent uniquement à identifier votre assureur actuel. Leur présence ne signifie pas qu’il existe un partenariat avec MAGA Assurances.</p>
            {filteredInsurers.length === 0 && <div className="notice amber"><b>Cette compagnie n’apparaît pas encore.</b><br />Sélectionnez « Autre compagnie » en recherchant « autre » : la demande générique reste valable auprès de tous les assureurs.</div>}
          </section>

          {selectedInsurer && <section className="insurer-guide-card" aria-live="polite">
            <div className="insurer-guide-heading">{selectedInsurer.logoUrl ? <img src={selectedInsurer.logoUrl} alt="" decoding="async" /> : <span aria-hidden="true">RI</span>}<div><p>Comment obtenir votre document</p><h2>{selectedInsurer.name}</h2>{selectedInsurer.insurer && <small>Votre contrat peut porter le nom de {selectedInsurer.insurer}.</small>}</div></div>
            <p className="insurer-instructions">{selectedInsurer.instructions}</p>
            {selectedInsurer.phone && <div className="insurer-contact"><span>Téléphone</span><strong>{selectedInsurer.phone}</strong>{selectedInsurer.hours && <small>{selectedInsurer.hours}</small>}</div>}

            <div className="request-template"><span>Modèle de demande</span><p>{riRequestText}</p><button className="secondary" type="button" onClick={async () => { await navigator.clipboard.writeText(riRequestText); setRequestCopied(true); }}>{requestCopied ? "✓ Demande copiée" : "Copier la demande"}</button></div>
            <p className="legal-delay">Votre assureur doit vous transmettre le relevé dans les 15 jours suivant votre demande expresse.</p>
            {error && <div className="button-error" role="alert">{error}</div>}
            <button className="primary waiting-button" type="button" disabled={busy} onClick={markRiRequested}>{busy ? "Envoi de votre lien de reprise…" : "J’ai demandé mon relevé"}</button>
          </section>}

          <div className="ri-return-upload"><div><b>Vous venez de recevoir votre relevé ?</b><span>Déposez-le directement, sans revenir en arrière.</span></div><label className={`upload upload-compact ${busy ? "upload-busy" : ""}`}><span className="upload-icon">⇧</span><b>{busy ? "Analyse en cours…" : "Ajouter mon relevé"}</b><small>PDF, JPG ou PNG · 10 Mo maximum</small><input type="file" accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" disabled={busy} onChange={handleRiFile} /></label></div>
        </div>}
        <div className="privacy-line">🔒 Le fichier est conservé dans votre dossier privé et n’est jamais joint à un e-mail.</div>
      </div>}

      {step === 4 && <div className="card card-wide"><div className="step-topline"><span className="step-bubble">4</span><div className="kicker">Votre carte grise</div></div><h1>Votre véhicule</h1><p className="intro">Munissez-vous de votre carte grise pour nous communiquer quelques renseignements.</p><div className="question-grid">
        <label className="form-field">Immatriculation du véhicule<span className="required-mark"> *</span><input required pattern="[A-Za-z]{2}-?[0-9]{3}-?[A-Za-z]{2}" className="plate" value={answers.registration} onChange={(event) => updateAnswer("registration", event.target.value.toUpperCase().replace(/[^A-Z0-9-]/g, "").slice(0, 9))} placeholder="AA-123-BB" /><span className="field-help">Immatriculation reprise automatiquement du relevé d’informations.</span></label>
        <SelectField label="Cette immatriculation est-elle identique à celle de la carte grise ?" value={answers.registrationMatchesCard} onChange={(value) => updateAnswer("registrationMatchesCard", value)}><option value="oui">Oui</option><option value="non">Non</option></SelectField>
        {answers.registrationMatchesCard === "non" && <div className="notice amber field-notice"><b>Les deux documents doivent concerner le même véhicule.</b><br />Rectifiez l’immatriculation pré-saisie ou remplacez le relevé d’informations à l’étape précédente.</div>}
        <label className="form-field">Date d’émission de la carte grise — rubrique I<span className="required-mark"> *</span><input required type="date" value={answers.cardIssueDate} onChange={(event) => updateAnswer("cardIssueDate", event.target.value)} /><span className="field-help">Date de l’immatriculation à laquelle se réfère la carte grise. À ne pas confondre avec la première mise en circulation, rubrique B.</span></label>
        <SelectField label="Le conducteur principal est-il titulaire de la carte grise ?" value={answers.registeredHolder} onChange={(value) => updateAnswer("registeredHolder", value)}><option value="oui">Oui</option><option value="non">Non</option></SelectField>
        {answers.registeredHolder === "non" && <SelectField label="Le propriétaire du véhicule est…" value={answers.ownerRelationship} onChange={(value) => updateAnswer("ownerRelationship", value)}><option>Votre conjoint</option><option>Un ascendant</option><option>Une personne morale</option><option>Autre</option></SelectField>}
        <SelectField label="Mode d’acquisition du véhicule" value={answers.acquisition} onChange={(value) => updateAnswer("acquisition", value)}><option>Comptant</option><option>Crédit</option><option>LOA ou LLD</option><option>Don ou héritage</option></SelectField>
      </div><div className="notice driver-read"><b>Le conducteur principal du véhicule est :</b><br />{answers.mainDriverName || "Cette information sera demandée à l’étape suivante si elle n’a pas pu être récupérée."}<span className="field-help">Information récupérée dans la rubrique « Conducteurs » du relevé d’informations.</span></div></div>}

      {step === 5 && <div className="card card-wide"><div className="step-topline"><span className="step-bubble">5</span><div className="kicker">Votre permis de conduire</div></div><h1>Le conducteur principal</h1><p className="intro">Munissez-vous de votre permis de conduire.</p>
        <div className="driver-summary"><span>Conducteur</span><b>{answers.mainDriverName || "À compléter"}{answers.mainDriverBirthDate ? ` · né(e) le ${formatDate(answers.mainDriverBirthDate)}` : ""}</b></div>
        <div className="question-grid">
          {!answers.mainDriverName && <label className="form-field">Nom et prénom du conducteur principal<span className="required-mark"> *</span><input required value={answers.mainDriverName} onChange={(event) => updateAnswer("mainDriverName", event.target.value)} /></label>}
          {!answers.mainDriverBirthDate && <label className="form-field">Date de naissance<span className="required-mark"> *</span><input required type="date" value={answers.mainDriverBirthDate} onChange={(event) => updateAnswer("mainDriverBirthDate", event.target.value)} /></label>}
          <label className="form-field">Téléphone mobile<span className="required-mark"> *</span><input required pattern="[+0-9 ()-]{10,}" type="tel" autoComplete="tel" value={answers.phone} onChange={(event) => updateAnswer("phone", event.target.value)} placeholder="06 12 34 56 78" /></label>
          <SelectField label="Situation matrimoniale" value={answers.maritalStatus} onChange={(value) => updateAnswer("maritalStatus", value)}><option>Célibataire</option><option>Concubin(e)</option><option>Marié(e)</option><option>Pacsé(e)</option><option>Divorcé(e)</option><option>Séparé(e)</option><option>Veuf ou veuve</option></SelectField>
          <label className="form-field">Date d’obtention du permis<span className="required-mark"> *</span><input required type="date" value={answers.licenceIssueDate} onChange={(event) => updateAnswer("licenceIssueDate", event.target.value)} /><span className="field-help">Reprise automatiquement du relevé d’informations.</span></label>
          <SelectField label="Pays d’obtention du permis" value={answers.licenceCountry} onChange={(value) => setAnswers((old) => ({ ...old, licenceCountry: value, accompaniedDriving: value === "En France - UE" ? old.accompaniedDriving : "", accompaniedDrivingType: value === "En France - UE" ? old.accompaniedDrivingType : "" }))}><option>En France - UE</option><option>Monaco</option><option>À l’étranger</option></SelectField>
          {answers.licenceCountry === "En France - UE" && <SelectField label="Permis obtenu en conduite accompagnée ?" value={answers.accompaniedDriving} onChange={(value) => updateAnswer("accompaniedDriving", value)}><option value="oui">Oui</option><option value="non">Non</option></SelectField>}
          {answers.licenceCountry === "En France - UE" && answers.accompaniedDriving === "oui" && <SelectField label="Type de conduite accompagnée" value={answers.accompaniedDrivingType} onChange={(value) => updateAnswer("accompaniedDrivingType", value)}><option>Conduite anticipée</option><option>Conduite supervisée</option><option>Conduite encadrée</option></SelectField>}
        </div>

        <div className="subsection"><h2>Stationnement habituel de votre véhicule</h2><div className="question-grid">
          <SelectField label="Le véhicule stationne…" value={answers.parkingType} onChange={(value) => updateAnswer("parkingType", value)}><option value="rue">Dans la rue</option><option value="autre">Dans un autre emplacement</option></SelectField>
          <label className="form-field">Code postal du stationnement<span className="required-mark"> *</span><input required pattern="\d{5}" inputMode="numeric" maxLength={5} value={answers.parkingPostalCode} onChange={(event) => updateAnswer("parkingPostalCode", event.target.value.replace(/\D/g, "").slice(0, 5))} placeholder="75001" /></label>
          {answers.parkingType === "rue" && <><SelectField label="Type de logement" value={answers.housingType} onChange={(value) => updateAnswer("housingType", value)}><option>Appartement</option><option>Maison</option><option>Autre</option></SelectField><SelectField label="Dont vous êtes" value={answers.housingTenure} onChange={(value) => updateAnswer("housingTenure", value)}><option>Propriétaire</option><option>Locataire</option><option>Autre</option></SelectField></>}
          {answers.parkingType === "autre" && <><SelectField label="Emplacement" value={answers.parkingCollective} onChange={(value) => updateAnswer("parkingCollective", value)} hint="Individuel : garage de maison, box ou cour privative. Collectif : autre emplacement en parking."><option>Individuel</option><option>Collectif</option></SelectField><SelectField label="Accès" value={answers.parkingClosed} onChange={(value) => updateAnswer("parkingClosed", value)} hint="Clos : accès réservé aux usagers. Non clos : accessible à toute personne."><option>Clos</option><option>Non clos</option></SelectField><SelectField label="Protection contre les intempéries" value={answers.parkingCovered} onChange={(value) => updateAnswer("parkingCovered", value)} hint="Couvert : protégé de la pluie, de la grêle et de la neige."><option>Couvert</option><option>Non couvert</option></SelectField></>}
        </div></div>

        <div className="subsection"><h2>Activité et utilisation du véhicule</h2><div className="question-grid">
          <SelectField label="Profession" value={answers.profession} onChange={(value) => updateAnswer("profession", value)}><option>Agriculteur</option><option>Artisan</option><option>Commerçant</option><option>Chef d’entreprise</option><option>Profession libérale</option><option>Cadre ou profession intellectuelle supérieure</option><option>Profession intermédiaire</option><option>Policier ou militaire</option><option>Employé</option><option>Ouvrier</option><option>Retraité</option><option>Inactif</option><option>Militaire du contingent</option><option>Étudiant</option><option>Autre</option></SelectField>
          {answers.profession === "Autre" && <label className="form-field">Précisez votre profession<span className="required-mark"> *</span><input required value={answers.professionOther} onChange={(event) => updateAnswer("professionOther", event.target.value)} /></label>}
          <div className="usage-field"><SelectField label="Usage du véhicule" value={answers.usage} onChange={(value) => updateAnswer("usage", value)}><option>Privé uniquement</option><option>Privé + trajets domicile-travail</option><option>Privé + déplacements professionnels</option></SelectField><details className="info-box usage-help"><summary>ⓘ Comment choisir le bon usage ?</summary><p><b>Privé :</b> aucun trajet professionnel ni domicile-travail.<br /><b>Privé + domicile-travail :</b> trajets vers un ou plusieurs lieux de travail fixes.<br /><b>Déplacements professionnels :</b> déplacements privés et professionnels.</p></details></div>
          <SelectField label="Distance parcourue par année" value={answers.mileage} onChange={(value) => updateAnswer("mileage", value)}><option>Moins de 5 000 km</option><option>De 5 000 à moins de 10 000 km</option><option>10 000 km ou plus</option></SelectField>
        </div></div>

        <div className="subsection"><h2>Chez vous, dans votre foyer</h2><div className="question-grid">
          <SelectField label="Nombre de personnes titulaires du permis de conduire" value={answers.householdDrivers} onChange={(value) => updateAnswer("householdDrivers", value)}><option>1</option><option>2</option><option>3</option><option>4 ou plus</option></SelectField>
          {answers.householdDrivers && answers.householdDrivers !== "1" && <SelectField label="Parmi elles, nombre de permis de moins de 3 ans sans assurance comme conducteur principal" value={answers.householdYoungLicences} onChange={(value) => updateAnswer("householdYoungLicences", value)}><option>0</option><option>1</option><option>2</option><option>3 ou plus</option></SelectField>}
          <SelectField label="Nombre de véhicules 4 roues dans le foyer" value={answers.householdVehicles} onChange={(value) => updateAnswer("householdVehicles", value)} hint="Véhicules utilisés à titre privé ou professionnel, hors camping-cars, véhicules de collection et voiturettes."><option>1</option><option>2</option><option>3</option><option>4 ou plus</option></SelectField>
        </div></div>
      </div>}

      {step === 6 && <div className="card card-wide"><div className="step-topline"><span className="step-bubble">6</span><div className="kicker">Une proposition réellement adaptée</div></div><h1>Protection et antécédents</h1>
        <fieldset className={`aggravation-panel ${answers.aggravations.length === 0 ? "incomplete-group" : ""}`}><legend>Le conducteur principal et/ou son conjoint/concubin ont-ils connu l’une de ces situations ? <span className="required-mark">*</span></legend><div className="aggravation-layout">
          <div className="aggravation-intro"><span className="history-icon">!</span><p>Choisissez toutes les situations concernées, ou sélectionnez « Aucune de ces situations ».</p></div>
          <div className="aggravation-periods">
            <section><h2>Depuis les 5 dernières années</h2>{["Conduite en état d’ivresse — 5 dernières années","Conduite sous l’emprise de stupéfiants — 5 dernières années","Délit de fuite — 5 dernières années"].map((item) => <label className="check aggravation-line" key={item}><input type="checkbox" checked={answers.aggravations.includes(item)} onChange={() => setAnswers((old) => ({ ...old, aggravations: old.aggravations.includes(item) ? old.aggravations.filter((value) => value !== item) : [...old.aggravations.filter((value) => value !== "Aucune de ces situations"), item] }))} /><span>{item.split(" — ")[0]}</span></label>)}</section>
            <section><h2>Depuis les 3 dernières années</h2>{["Suspension de permis supérieure à 60 jours — 3 dernières années","Annulation de permis — 3 dernières années","Défaut d’assurance — 3 dernières années"].map((item) => <label className="check aggravation-line" key={item}><input type="checkbox" checked={answers.aggravations.includes(item)} onChange={() => setAnswers((old) => ({ ...old, aggravations: old.aggravations.includes(item) ? old.aggravations.filter((value) => value !== item) : [...old.aggravations.filter((value) => value !== "Aucune de ces situations"), item] }))} /><span>{item.split(" — ")[0]}</span></label>)}</section>
            <button className={`none-choice ${answers.aggravations.includes("Aucune de ces situations") ? "selected" : ""}`} type="button" onClick={() => setAnswers((old) => ({ ...old, aggravations: old.aggravations.includes("Aucune de ces situations") ? [] : ["Aucune de ces situations"] }))}>Aucune de ces situations</button>
          </div>
        </div></fieldset>
        <div className="question-grid">
          <SelectField label="Votre priorité" value={answers.protectionPriority} onChange={(value) => updateAnswer("protectionPriority", value)}><option>Réduire au maximum ma cotisation</option><option>Équilibrer prix et protection</option><option>Renforcer ma protection</option><option>Je souhaite être conseillé(e)</option></SelectField>
          <div className="guarantee-field"><SelectField label="Niveau de garanties souhaité" value={answers.desiredFormula} onChange={(value) => updateAnswer("desiredFormula", value)}><option>Tiers</option><option>Tiers étendu</option><option>Tous risques</option></SelectField>{answers.desiredFormula && (() => { const detail = guaranteeDetails[answers.desiredFormula]; return <section className="coverage-details" aria-live="polite"><div className="coverage-title"><span aria-hidden="true">ⓘ</span><div><b>{answers.desiredFormula}</b><strong>« {detail.tagline} »</strong></div></div><p>{detail.coverage}</p>{detail.limitation && <p><b>Ce qui n’est pas couvert :</b> {detail.limitation}</p>}<p><b>En clair :</b> {detail.image}</p><p><b>Pour qui :</b> {detail.audience}</p><small>Les garanties exactes, limites, franchises et exclusions dépendront de la proposition remise.</small></section>; })()}</div>
        </div><div className="notice"><b>Pourquoi ces questions ?</b><br />Elles peuvent modifier l’acceptation du dossier, les garanties proposées ou le tarif.</div>
      </div>}

      {step === 7 && <div className="card recap"><div className="success-mark">✓</div><div className="kicker">Votre demande d’étude est complète</div><h1>Dernière vérification avant transmission</h1><div className="recap-grid"><div><span>Conducteur principal</span><b>{answers.mainDriverName || "À vérifier"}</b></div><div><span>Adresse e-mail</span><b>{user?.email || "À vérifier"}</b></div><div><span>N° de téléphone</span><b>{answers.phone || "À vérifier"}</b></div><div><span>Véhicule</span><b>{extracted.vehicleMake || "Véhicule"} · {answers.registration}</b></div><div><span>Bonus-malus</span><b>{extracted.crm || "Repris du relevé"}</b></div><div><span>Relevé d’informations émis le</span><b>{formatDate(extracted.documentDate)}</b></div><div><span>Usage</span><b>{answers.usage}</b></div><div><span>Niveau de protection souhaité</span><b>{answers.desiredFormula}</b></div></div><label className="check consent-check"><input required type="checkbox" checked={consentData} onChange={(event) => setConsentData(event.target.checked)} /><span>J’autorise MAGA Assurances à utiliser les informations et le relevé transmis pour étudier ma demande d’assurance automobile. J’ai pris connaissance de la politique de confidentialité.</span></label><label className="check consent-check"><input required type="checkbox" checked={consentAccuracy} onChange={(event) => setConsentAccuracy(event.target.checked)} /><span>Je certifie l’exactitude des informations communiquées et comprends que toute proposition restera soumise à l’étude de la demande, aux justificatifs nécessaires et à l’acceptation de l’assureur.</span></label><button className="primary submit" type="button" disabled={!canContinue || busy} onClick={submitDossier}>{busy ? "Transmission…" : dossier?.status === "submitted" ? "TRANSMETTRE MES MODIFICATIONS" : "TRANSMETTRE MA DEMANDE"}<span>→</span></button></div>}

      {step === 8 && <div className="card completion"><div className="completion-icon">✓</div><div className="kicker">Demande transmise</div><h1>Merci, votre étude peut commencer.</h1><p className="intro">Votre relevé et vos réponses sont enregistrés dans votre espace sécurisé. MAGA Assurances pourra maintenant étudier une proposition chiffrée adaptée à votre situation.</p>
        {emailDelivery === "sent" && <div className="notice email-confirmation"><b>✓ Accusé de réception envoyé</b><br />Consultez votre boîte e-mail et, si nécessaire, vos courriers indésirables. Aucun document officiel n’est joint au message.</div>}
        {emailDelivery === "sending" && <div className="notice email-confirmation"><b>Envoi de votre accusé de réception…</b></div>}
        {emailDelivery === "failed" && <div className="notice amber"><b>Votre demande est bien enregistrée.</b><br />L’e-mail de confirmation n’a pas encore pu partir. Vous pouvez le relancer sans remplir à nouveau le questionnaire.</div>}
        {emailDelivery === "idle" && <div className="notice"><b>Votre demande est bien enregistrée.</b><br />Vous pouvez maintenant demander l’envoi de votre accusé de réception.</div>}
        <div className="completion-steps"><div><span>1</span><p><b>Analyse de la demande</b>MAGA Assurances vérifie les informations et les pièces.</p></div><div><span>2</span><p><b>Proposition personnalisée</b>Vous comparez le tarif, les garanties et les franchises.</p></div><div><span>3</span><p><b>Vous décidez librement</b>Si vous acceptez, MAGA Assurances gère la mise en place et la résiliation.*</p></div></div>
        <div className="completion-actions">{emailDelivery !== "sent" && <button className="primary" type="button" disabled={emailDelivery === "sending"} onClick={() => void sendCompletionEmails()}>{emailDelivery === "sending" ? "Envoi en cours…" : emailDelivery === "failed" ? "Renvoyer l’accusé de réception" : "Envoyer mon accusé de réception"}</button>}<button className="secondary" type="button" onClick={() => setStep(10)}>Reprendre mon dossier</button><button className="back home-button" type="button" onClick={signOut}>Quitter — retour à l’accueil</button></div>
      </div>}

      {step === 9 && <div className="card card-wide documents-portal"><div className="documents-portal-heading"><div><div className="kicker">Après acceptation de votre proposition</div><h1>Complétez votre dossier de souscription</h1><p className="intro">Déposez les documents demandés ci-dessous. Chaque fichier est enregistré dans votre espace privé et n’est jamais joint à un e-mail.</p></div><div className={`documents-progress ${subscriptionDocumentsComplete ? "complete" : ""}`}><strong>{uploadedDocumentCount}/{subscriptionDocumentSlots.length}</strong><span>{subscriptionDocumentsComplete ? "Dossier complet" : "Pièces déposées"}</span></div></div>
        {subscriptionDocumentsComplete && <div className="documents-complete"><span>✓</span><div><b>Toutes les pièces ont bien été déposées.</b><p>MAGA Assurances peut poursuivre la mise en place de votre contrat.</p></div></div>}
        <div className="document-upload-grid">{subscriptionDocumentSlots.map((slot) => { const uploaded = subscriptionDocuments[slot.type]; const isUploading = uploadingDocument === slot.type; return <article className={`document-upload-card ${uploaded ? "uploaded" : ""}`} key={slot.type}><span className="document-marker document-preview">{slot.imageUrl && <img src={slot.imageUrl} alt={`Exemple : ${slot.title}`} />}{uploaded && <i aria-label="Pièce déposée">✓</i>}</span><div><h2>{slot.title}</h2><p>{uploaded ? uploaded.original_name : slot.hint}</p><small>PDF, JPG ou PNG · 10 Mo maximum</small></div><label className={`secondary document-upload-button ${isUploading ? "disabled" : ""}`}>{isUploading ? "Enregistrement…" : uploaded ? "Remplacer" : "Ajouter"}<input type="file" accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" disabled={!!uploadingDocument} onChange={(event) => void handleSubscriptionFile(slot.type, event)} /></label></article>})}</div>
        <div className="optional-document"><div><span>Facultatif</span><h2>Vous souhaitez ajouter une autre pièce ?</h2><p>Vous pouvez joindre librement un document complémentaire utile à votre dossier.</p></div>{(() => { const slot = otherDocumentSlot; const uploaded = subscriptionDocuments[slot.type]; const isUploading = uploadingDocument === slot.type; return <article className={`document-upload-card ${uploaded ? "uploaded" : ""}`}><span className="document-marker">{uploaded ? "✓" : slot.marker}</span><div><h2>{slot.title}</h2><p>{uploaded ? uploaded.original_name : slot.hint}</p><small>PDF, JPG ou PNG · 10 Mo maximum</small></div><label className={`secondary document-upload-button ${isUploading ? "disabled" : ""}`}>{isUploading ? "Enregistrement…" : uploaded ? "Remplacer" : "Ajouter"}<input type="file" accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png" disabled={!!uploadingDocument} onChange={(event) => void handleSubscriptionFile(slot.type, event)} /></label></article>; })()}</div>
        <div className="privacy-line">🔒 Seuls vous-même et MAGA Assurances pouvez accéder à ces documents.</div>
        {documentsDelivery === "sent" && <div className="notice email-confirmation"><b>✓ Récapitulatif envoyé</b><br />{subscriptionDocumentsComplete ? "Toutes les pièces obligatoires sont signalées à MAGA Assurances." : `${uploadedDocumentCount} pièce${uploadedDocumentCount > 1 ? "s" : ""} obligatoire${uploadedDocumentCount > 1 ? "s" : ""} transmise${uploadedDocumentCount > 1 ? "s" : ""} sur ${subscriptionDocumentSlots.length}. Vous avez reçu par e-mail la liste des pièces restantes et le lien pour compléter votre dossier.`}</div>}
        {documentsDelivery === "failed" && <div className="notice amber"><b>Vos pièces sont bien enregistrées.</b><br />L’alerte à MAGA Assurances n’a pas encore pu partir. Vous pouvez réessayer sans recharger les fichiers.</div>}
        <div className="documents-actions"><button className="primary" type="button" disabled={!uploadedAnyDocument || !!uploadingDocument || documentsDelivery === "sending"} onClick={() => void sendSubscriptionDocuments()}>{documentsDelivery === "sending" ? "Envoi en cours…" : subscriptionDocumentsComplete ? "Envoyer le dossier complet" : "Envoyer les pièces déposées"}<span>→</span></button><button className="secondary" type="button" disabled={documentsDelivery === "sending"} onClick={signOut}>Revenir plus tard</button></div>
        {!uploadedAnyDocument && <p className="documents-action-help">Déposez au moins une pièce pour pouvoir transmettre un premier récapitulatif.</p>}
      </div>}

      {step === 10 && <div className="card card-wide workspace-dashboard"><div className="step-topline"><span className="step-bubble">🔒</span><div className="kicker">Votre espace personnel</div></div><h1>Retrouvez et complétez votre dossier</h1><p className="intro">Votre demande reste accessible avec la même adresse e-mail. Chaque action dépend de l’avancement réel de votre étude.</p><div className="workspace-status"><span>✓</span><div><b>{dossier ? (dossier.workflow_status === "quotes_ready" ? "Vos propositions sont disponibles" : dossier.workflow_status === "quote_selected" ? "Votre choix est enregistré" : "Demande transmise") : "Demande en cours"}</b><p>{riFileName ? `Relevé enregistré : ${riFileName}` : "Votre relevé d’informations reste à déposer."}</p></div></div><div className="workspace-actions"><article><span>01</span><div><h2>Reprendre mon dossier</h2><p>Ajustez vos déclarations ou remplacez votre relevé d’informations.</p></div><button className="primary" type="button" onClick={openDossierForEditing}>Reprendre mon dossier <span>→</span></button></article><article><span>02</span><div><h2>Consulter mes propositions</h2><p>Comparez les tarifs, garanties, franchises et le conseil de MAGA Assurances.</p></div><button className="secondary" type="button" disabled={!dossier || !["quotes_ready", "quote_selected", "documents_pending", "documents_complete", "ready_for_edi", "sent_to_edi", "signed", "finalized"].includes(dossier.workflow_status)} onClick={async () => { if (!dossier) return; setWorkspaceMode(false); setQuotesMode(true); window.history.replaceState({}, "", `${window.location.pathname}?devis=1`); await loadPublishedQuotes(dossier.id); setStep(12); }}>Voir mes propositions</button></article><article><span>03</span><div><h2>Déposer mes pièces</h2><p>Après votre choix, chargez votre CNI, votre permis, la carte grise et votre RIB.</p></div><button className="secondary" type="button" disabled={!dossier || !["quote_selected", "documents_pending", "documents_complete", "ready_for_edi", "sent_to_edi", "signed", "finalized"].includes(dossier.workflow_status)} onClick={() => void openSubscriptionDocuments()}>Déposer mes pièces</button></article></div><div className="privacy-line">🔒 Chaque nouvel accès est protégé par un code reçu par e-mail.</div></div>}

      {step === 11 && <div className="card completion documents-success-page"><div className="completion-icon">✓</div><div className="kicker">Pièces transmises</div><h1>{subscriptionDocumentsComplete ? "Votre dossier de souscription est complet." : "Vos pièces ont bien été transmises."}</h1><p className="intro">MAGA Assurances a bien été informée de votre dépôt sécurisé. Un récapitulatif vous a également été envoyé par e-mail.</p><div className="documents-success-summary"><span>✓</span><div><b>{uploadedDocumentCount}/{subscriptionDocumentSlots.length} pièces obligatoires déposées</b><p>{subscriptionDocumentsComplete ? "Toutes les pièces nécessaires sont maintenant enregistrées dans votre espace sécurisé." : "Vous pourrez revenir dans votre espace pour ajouter les pièces encore attendues."}</p></div></div><div className="notice"><b>Aucun document n’est joint aux e-mails.</b><br />Les fichiers restent uniquement accessibles dans votre espace privé sécurisé.</div><div className="completion-actions"><button className="primary" type="button" onClick={returnToWorkspace}>Reprendre mon dossier <span>→</span></button><button className="back home-button" type="button" onClick={signOut}>Quitter — retour à l’accueil</button></div></div>}

      {step === 12 && <div className="card card-wide quotes-portal"><div className="step-topline"><span className="step-bubble">🔒</span><div className="kicker">Vos propositions personnalisées</div></div><h1>Comparez et choisissez en toute connaissance de cause</h1><p className="intro">MAGA Assurances a étudié votre situation. Consultez chaque devis complet avant d’enregistrer votre choix. Les garanties, limites, franchises et exclusions détaillées figurent dans les documents PDF.</p>
        {comparisonPdf && <section className="comparison-first"><h2>Votre comparatif des offres</h2><ComparisonPreview path={comparisonPdf.file_path} /><button className="primary" onClick={() => void openQuotePdf(comparisonPdf)}>Consulter le comparatif PDF</button></section>}
        {!publishedQuotes.length ? <div className="quotes-empty"><span>⌛</span><div><b>Votre étude est en cours</b><p>Vous recevrez un e-mail dès que vos propositions seront disponibles.</p></div></div> : <div className="quote-comparison-grid">{publishedQuotes.map((quote) => <article className={quote.status === "selected" ? "selected" : ""} key={quote.id}><div className="quote-card-top"><span>Proposition {quote.position}</span>{quote.status === "selected" && <em>Votre choix</em>}</div><h2>{quote.formula_name}</h2><p className="quote-insurer">{quote.insurer_name}</p><div className="quote-price"><strong>{quote.monthly_premium ? formatMoney(quote.monthly_premium) : formatMoney(quote.annual_premium / 12)}</strong><span>/ mois</span><small>{formatMoney(quote.annual_premium)} par an</small></div><dl><div><dt>Garanties principales</dt><dd>{quote.guarantees_summary || "Consultez le devis complet"}</dd></div><div><dt>Franchises principales</dt><dd>{quote.deductibles_summary || "Consultez le devis complet"}</dd></div><div className="quote-advice"><dt>Pourquoi cette proposition ?</dt><dd>{quote.advice || "Cette solution a été retenue après l’étude de vos besoins et de votre situation."}</dd></div></dl>{quote.valid_until && <p className="quote-validity">Proposition valable jusqu’au {formatDate(quote.valid_until)}</p>}<button className="secondary" type="button" onClick={() => void openQuotePdf(quote)}>Consulter le devis complet</button><button className="primary" type="button" disabled={quote.status === "selected" || !!dossier?.selected_quote_id || quoteSelectionBusy === quote.id} onClick={() => void selectQuote(quote)}>{quote.status === "selected" ? "✓ Proposition choisie" : quoteSelectionBusy === quote.id ? "Enregistrement…" : "Choisir et poursuivre ma souscription"}<span>→</span></button></article>)}</div>}
        {dossier?.selected_quote_id && <div className="quote-choice-next"><span>✓</span><div><b>Votre choix est enregistré</b><p>Vous pouvez maintenant transmettre les justificatifs nécessaires à la mise en place du contrat.</p></div><button className="primary" onClick={() => void openSubscriptionDocuments()}>Déposer mes pièces <span>→</span></button></div>}
        <div className="notice"><b>Besoin d’un conseil avant de décider ?</b><br />Contactez MAGA Assurances au 09 78 25 08 58. Votre choix ne deviendra définitif qu’après contrôle des justificatifs, acceptation de l’assureur et signature des documents contractuels.</div>
      </div>}
    </section>

    {step === 1 && eligibility.insured === "non" ? <nav className="actions"><button className="back" onClick={() => setStep(0)}>← Retour à l’accueil</button><div className="autosave">{callbackStatus === "sent" ? "✓ Demande de rappel transmise" : ""}</div></nav> : step === 3 && eligibility.riStatus !== "disponible" ? <nav className="actions"><button className="back" onClick={() => setStep(2)}>← Retour</button><div className="autosave">{eligibility.riRequested ? "✓ Dossier conservé en attente du RI" : "Sélectionnez votre assureur"}</div><button className="secondary" type="button" onClick={signOut}>Quitter et revenir plus tard</button></nav> : step > 0 && step < 7 && <nav className="actions"><button className="back" onClick={() => setStep((current) => Math.max(0, current - 1))}>← Retour</button><div className="autosave">{!canContinue ? <span className="missing-footer">Complétez les rubriques signalées en orange</span> : user ? "✓ Sauvegarde sécurisée" : ""}</div><button className="primary" disabled={!canContinue || busy} onClick={next}>Continuer <span>→</span></button></nav>}
    {step === 7 && <nav className="actions"><button className="back" onClick={() => setStep(6)}>← Modifier</button><div className="autosave">✓ Sauvegarde sécurisée</div></nav>}
    <footer className="legal-footer"><p><strong>MAGA Assurances</strong> — Société de Courtage d’Assurances — Siège social : 14, Avenue de l’Opéra – 75001 Paris — SAS au capital de 40 000 € — 953 299 195 R.C.S. Paris — N° TVA : FR37953299195 — Code NAF/APE : 6622Z — N° ORIAS : 23 0049 53 – COA — <a href="https://www.orias.fr/">www.orias.fr</a> — Société exerçant sous le contrôle de l’ACPR — <a href="https://acpr.banque-france.fr/">acpr.banque-france.fr</a> — Site internet : <a href="https://maga-assurances.com">maga-assurances.com</a></p><span className="legal-note">* Sous réserve des conditions légales et contractuelles de résiliation. · Crédits photos : Shutterstock.</span><nav><a href="https://maga-assurances.com/politique-de-confidentialite/">Confidentialité</a><a href="https://maga-assurances.com/mentions-legales/">Mentions légales</a></nav></footer>
  </main>;
}
