"use client"

import { useEffect, useState } from "react"
import { Download } from "lucide-react"
import { useSearchParams } from "next/navigation"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import { OrgSettingsSection } from "@/components/admin/settings/org-settings-form"
import { TechBrandSelectLabel } from "@/components/admin/settings/tech-brand-select-label"
import { SettingsField, SettingsGrid } from "@/components/settings/settings-kit"
import {
  type DNSCheckReport,
  type MailDomain,
  type MigrationSharedDrive,
  type MigrationJob,
  type MigrationJobAuditItem,
  type MigrationProject,
  useActivateMigrationProject,
  useCreateMigrationInvite,
  useCreateMigrationProject,
  useCutoverMigrationProject,
  useImportMigrationInvites,
  useImportMigrationRoster,
  useMicrosoftMigrationAdminConsentURL,
  useMigrationJobAudit,
  useMigrationJobAuditSummary,
  useMigrationProjectJobs,
  useMigrationProjects,
  useMigrationRoster,
  useMigrationSharedDrives,
  useApproveMigrationSharedDrive,
  useRejectMigrationSharedDrive,
  useUpdateMigrationSharedDriveMode,
  downloadMigrationJobAudit,
  usePreflightCutoverDNS,
  useResetMigrationJobCursor,
  useRetryMigrationFailedJobs,
  useRetryMigrationJob,
} from "@/lib/api/hooks/use-hosted-mail"
import { ULTICAL_APP_NAME } from "@/lib/suite/page-metadata"

const SERVICE_LABELS: Record<string, string> = {
  mail: "Mail",
  contacts: "Contacts",
  calendar: ULTICAL_APP_NAME,
  drive: "Drive",
}

const AUTH_MODE_LABELS: Record<string, string> = {
  oauth: "OAuth utilisateur",
  google_dwd: "Google DWD (service account)",
  microsoft_app: "Microsoft app-only (client credentials)",
}

function statusVariant(status: string): "default" | "secondary" | "destructive" | "outline" {
  switch (status) {
    case "completed":
    case "active":
    case "cutover":
    case "claimed":
    case "invited":
      return "default"
    case "running":
    case "pending":
      return "secondary"
    case "failed":
      return "destructive"
    default:
      return "outline"
  }
}

function jobImportedCount(job: MigrationJob): string {
  const imported = job.stats_json?.imported
  if (typeof imported !== "number") return "—"
  const total = job.stats_json?.estimated_total
  if (typeof total === "number" && total > 0) {
    return `${Math.round(imported)} / ~${Math.round(total)}`
  }
  return String(Math.round(imported))
}

export function MigrationProjectsPanel({ domains }: { domains: MailDomain[] }) {
  const params = useSearchParams()
  const projectsQuery = useMigrationProjects()
  const createProject = useCreateMigrationProject()
  const activateProject = useActivateMigrationProject()
  const cutoverProject = useCutoverMigrationProject()
  const msAdminConsent = useMicrosoftMigrationAdminConsentURL()

  const [projectName, setProjectName] = useState("")
  const [sourceProvider, setSourceProvider] = useState("google")
  const [authMode, setAuthMode] = useState("oauth")
  const [domainId, setDomainId] = useState("")
  const [inviteEmail, setInviteEmail] = useState("")
  const [alternateEmails, setAlternateEmails] = useState("")
  const [csvEmails, setCsvEmails] = useState("")
  const [rosterCsv, setRosterCsv] = useState("")
  const [rosterImportSummary, setRosterImportSummary] = useState<string | null>(null)
  const [selectedProjectId, setSelectedProjectId] = useState("")
  const [msTenant, setMsTenant] = useState("common")
  const [consentBanner, setConsentBanner] = useState<string | null>(null)
  const [cutoverReport, setCutoverReport] = useState<DNSCheckReport | null>(null)
  const [cutoverError, setCutoverError] = useState<string | null>(null)
  const [dnsSource, setDnsSource] = useState<"cutover" | "persisted" | "live" | null>(null)
  const [auditJobId, setAuditJobId] = useState<string | null>(null)

  const projects = projectsQuery.data?.projects ?? []
  const activeProjectId = selectedProjectId || projects[0]?.id || ""
  const activeProject = projects.find((p) => p.id === activeProjectId)
  const createInvite = useCreateMigrationInvite(activeProjectId)
  const importInvites = useImportMigrationInvites(activeProjectId)
  const importRoster = useImportMigrationRoster(activeProjectId)
  const rosterQuery = useMigrationRoster(activeProjectId, Boolean(activeProjectId))
  const jobsQuery = useMigrationProjectJobs(activeProjectId, Boolean(activeProjectId))
  const retryJob = useRetryMigrationJob(activeProjectId)
  const resetCursor = useResetMigrationJobCursor(activeProjectId)
  const retryFailed = useRetryMigrationFailedJobs(activeProjectId)
  const preflightDNS = usePreflightCutoverDNS(activeProjectId)
  const updateSharedDriveMode = useUpdateMigrationSharedDriveMode(activeProjectId)
  const sharedDrivesQuery = useMigrationSharedDrives(
    activeProjectId,
    Boolean(activeProjectId && activeProject?.source_provider === "google")
  )
  const approveSharedDrive = useApproveMigrationSharedDrive(activeProjectId)
  const rejectSharedDrive = useRejectMigrationSharedDrive(activeProjectId)

  useEffect(() => {
    const consent = params.get("microsoft_admin_consent")
    if (consent === "success") {
      const tenant = params.get("tenant")
      const projectId = params.get("project_id")
      setConsentBanner(
        tenant
          ? `Consentement admin Microsoft enregistré (tenant ${tenant}${projectId ? `, projet ${projectId.slice(0, 8)}…` : ""}).`
          : "Consentement admin Microsoft enregistré."
      )
      void projectsQuery.refetch()
    } else if (consent === "error") {
      setConsentBanner("Échec du consentement admin Microsoft — vérifiez le tenant et réessayez.")
      void projectsQuery.refetch()
    }
  }, [params, projectsQuery])

  useEffect(() => {
    setCutoverReport(null)
    setCutoverError(null)
    setDnsSource(null)
    setAuditJobId(null)
  }, [activeProjectId])

  useEffect(() => {
    if (activeProject?.cutover_dns) {
      setDnsSource((prev) => (prev === "cutover" || prev === "live" ? prev : "persisted"))
    }
  }, [activeProject?.cutover_dns, activeProjectId])

  const dnsReport =
    cutoverReport ?? activeProject?.cutover_dns ?? preflightDNS.data?.dns ?? null

  const failedCount = (jobsQuery.data?.jobs ?? []).filter((j) => j.status === "failed").length

  return (
    <OrgSettingsSection
      title="Projets de migration"
      description="Import Google Workspace / Microsoft 365, invitations, suivi des jobs et bascule MX."
    >
      {consentBanner && (
        <p
          className={`mb-4 rounded-md px-3 py-2 text-sm ${
            consentBanner.startsWith("Échec")
              ? "bg-destructive/10 text-destructive"
              : "bg-green-500/10 text-green-700"
          }`}
        >
          {consentBanner}
        </p>
      )}

      <SettingsGrid>
        <SettingsField label="Nom du projet" htmlFor="project-name">
          <Input
            id="project-name"
            className="h-9"
            value={projectName}
            onChange={(e) => setProjectName(e.target.value)}
            placeholder="Migration ACME 2026"
          />
        </SettingsField>
        <SettingsField label="Source">
          <Select
            value={sourceProvider}
            onValueChange={(value) => {
              setSourceProvider(value)
              if (value !== "google" && authMode === "google_dwd") {
                setAuthMode("oauth")
              }
              if (value !== "microsoft" && authMode === "microsoft_app") {
                setAuthMode("oauth")
              }
            }}
          >
            <SelectTrigger className="h-9">
              <SelectValue>
                <TechBrandSelectLabel brand={sourceProvider}>
                  {sourceProvider === "google" ? "Google Workspace" : "Microsoft 365"}
                </TechBrandSelectLabel>
              </SelectValue>
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="google">
                <TechBrandSelectLabel brand="google">Google Workspace</TechBrandSelectLabel>
              </SelectItem>
              <SelectItem value="microsoft">
                <TechBrandSelectLabel brand="microsoft">Microsoft 365</TechBrandSelectLabel>
              </SelectItem>
            </SelectContent>
          </Select>
        </SettingsField>
        <SettingsField label="Mode d'authentification">
          <Select value={authMode} onValueChange={setAuthMode}>
            <SelectTrigger className="h-9">
              <SelectValue>
                <TechBrandSelectLabel brand={authMode === "oauth" ? "oauth" : authMode}>
                  {AUTH_MODE_LABELS[authMode] ?? authMode}
                </TechBrandSelectLabel>
              </SelectValue>
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="oauth">
                <TechBrandSelectLabel brand="oauth">OAuth utilisateur</TechBrandSelectLabel>
              </SelectItem>
              <SelectItem value="google_dwd" disabled={sourceProvider !== "google"}>
                <TechBrandSelectLabel brand="google">
                  Google DWD (service account)
                </TechBrandSelectLabel>
              </SelectItem>
              <SelectItem value="microsoft_app" disabled={sourceProvider !== "microsoft"}>
                <TechBrandSelectLabel brand="microsoft">
                  Microsoft app-only (client credentials)
                </TechBrandSelectLabel>
              </SelectItem>
            </SelectContent>
          </Select>
        </SettingsField>
        <SettingsField label="Domaine mail (optionnel)">
          <Select value={domainId || "__none__"} onValueChange={(v) => setDomainId(v === "__none__" ? "" : v)}>
            <SelectTrigger className="h-9">
              <SelectValue placeholder="Aucun" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="__none__">Aucun</SelectItem>
              {domains.map((domain) => (
                <SelectItem key={domain.id} value={domain.id}>
                  {domain.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </SettingsField>
      </SettingsGrid>

      <div className="mt-4">
        <Button
          disabled={!projectName || createProject.isPending}
          onClick={() => {
            void createProject
              .mutateAsync({
                name: projectName,
                source_provider: sourceProvider,
                domain_id: domainId || undefined,
                auth_mode: authMode,
              })
              .then((project) => {
                setProjectName("")
                setSelectedProjectId(project.id)
              })
          }}
        >
          Créer le projet
        </Button>
      </div>

      <ul className="mt-6 space-y-3">
        {projects.map((project) => (
          <ProjectRow
            key={project.id}
            project={project}
            selected={project.id === activeProjectId}
            onSelect={() => setSelectedProjectId(project.id)}
            onActivate={() => {
              setSelectedProjectId(project.id)
              void activateProject.mutateAsync(project.id)
            }}
            onCutover={() => {
              setCutoverError(null)
              void cutoverProject.mutateAsync(project.id).then(
                (res) => {
                  setCutoverReport(res.dns)
                  setDnsSource("cutover")
                },
                (err) => {
                  setCutoverReport(null)
                  if (err instanceof ApiRequestError && err.code === "migration_cutover_mx_not_ready") {
                    const details = err.details as { dns?: DNSCheckReport } | undefined
                    if (details?.dns) {
                      setCutoverReport(details.dns)
                      setDnsSource("cutover")
                    }
                    setCutoverError(err.message)
                  } else {
                    setCutoverError(err instanceof Error ? err.message : "Cutover failed")
                  }
                }
              )
            }}
          />
        ))}
      </ul>

      {activeProject?.source_provider === "microsoft" && (
        <div className="mt-6  space-y-3 rounded-lg border border-mail-border p-4">
            <h3 className="font-medium">Consentement admin Microsoft</h3>
          <p className="text-sm text-muted-foreground">
            Requis pour les migrations Microsoft 365
            {activeProject.auth_mode === "microsoft_app"
              ? " en mode app-only (permissions application : Mail.Read, Calendars.Read, Contacts.Read, Files.Read.All)."
              : " en mode organisation (permissions applicatives)."}
          </p>
          {activeProject.microsoft_admin_consent_at ? (
            <p className="text-sm text-green-700">
              Consentement accordé
              {activeProject.microsoft_tenant_id
                ? ` — tenant ${activeProject.microsoft_tenant_id}`
                : ""}
              {activeProject.microsoft_admin_consent_at
                ? ` (${new Date(activeProject.microsoft_admin_consent_at).toLocaleString()})`
                : ""}
            </p>
          ) : activeProject.microsoft_admin_consent_error ? (
            <p className="text-sm text-destructive">{activeProject.microsoft_admin_consent_error}</p>
          ) : (
            <p className="text-sm text-amber-700">Consentement non enregistré pour ce projet.</p>
          )}
          <div className="grid gap-4 md:grid-cols-[1fr_auto]">
            <Input
              value={msTenant}
              onChange={(e) => setMsTenant(e.target.value)}
              placeholder="common ou tenant ID"
            />
            <Button
              variant="outline"
              disabled={msAdminConsent.isPending || !activeProjectId}
              onClick={() => {
                void msAdminConsent
                  .mutateAsync({ tenant: msTenant, projectId: activeProjectId })
                  .then((res) => {
                    window.location.href = res.url
                  })
              }}
            >
              Consentement admin MS
            </Button>
          </div>
        </div>
      )}

      {activeProjectId && (
        <>
          <div className="mt-6 space-y-3 rounded-lg border border-mail-border p-4">
            <div className="flex flex-wrap items-center justify-between gap-2">
              <h3 className="font-medium">Pré-vérification DNS (cutover)</h3>
              <Button
                size="sm"
                variant="outline"
                disabled={preflightDNS.isFetching}
                onClick={() => {
                  void preflightDNS.refetch().then((res) => {
                    if (res.data?.dns) setDnsSource("live")
                  })
                }}
              >
                {preflightDNS.isFetching ? "Vérification…" : "Vérifier DNS"}
              </Button>
            </div>
            {cutoverError && (
              <p className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
                {cutoverError}
              </p>
            )}
            {dnsReport && (
              <>
                {dnsSource === "persisted" && activeProject?.cutover_at && (
                  <p className="text-xs text-muted-foreground">
                    Rapport enregistré au cutover (
                    {new Date(activeProject.cutover_at).toLocaleString()}).
                  </p>
                )}
                {dnsSource === "live" && (
                  <p className="text-xs text-muted-foreground">
                    Vérification DNS live (non enregistrée — lancez la bascule MX pour persister).
                  </p>
                )}
                <DNSReportCard report={dnsReport} />
              </>
            )}
            {!dnsReport && activeProject?.domain_id && (
              <p className="text-sm text-muted-foreground">
                Aucun rapport DNS enregistré — vérifiez live ou lancez la bascule MX.
              </p>
            )}
          </div>

          {activeProject?.source_provider === "google" && (
            <SharedDrivesPanel
              project={activeProject}
              drives={sharedDrivesQuery.data?.shared_drives ?? []}
              loading={sharedDrivesQuery.isLoading}
              onModeChange={(mode) => void updateSharedDriveMode.mutateAsync(mode)}
              modePending={updateSharedDriveMode.isPending}
              onApprove={(driveId) => void approveSharedDrive.mutateAsync(driveId)}
              onReject={(driveId) => void rejectSharedDrive.mutateAsync(driveId)}
              actionPending={approveSharedDrive.isPending || rejectSharedDrive.isPending}
            />
          )}

          <div className="mt-8 space-y-4 rounded-lg border border-mail-border p-4">
            <div className="flex flex-wrap items-center justify-between gap-2">
              <h3 className="font-medium">Jobs de migration</h3>
              <Button
                size="sm"
                variant="outline"
                disabled={failedCount === 0 || retryFailed.isPending}
                onClick={() => void retryFailed.mutateAsync()}
              >
                Relancer les échecs ({failedCount})
              </Button>
            </div>
            <JobsTable
              jobs={jobsQuery.data?.jobs ?? []}
              loading={jobsQuery.isLoading}
              auditJobId={auditJobId}
              onAudit={(jobId) => setAuditJobId((prev) => (prev === jobId ? null : jobId))}
              onRetry={(jobId) => void retryJob.mutateAsync(jobId)}
              onResetCursor={(jobId) => void resetCursor.mutateAsync(jobId)}
              retryPending={retryJob.isPending}
              resetPending={resetCursor.isPending}
            />
            {auditJobId && (
              <JobAuditPanel projectId={activeProjectId} jobId={auditJobId} jobs={jobsQuery.data?.jobs ?? []} />
            )}
          </div>

          <div className="mt-8 space-y-4 rounded-lg border border-mail-border p-4">
            <h3 className="font-medium">Invitations utilisateurs</h3>
            <div className="grid gap-4 md:grid-cols-[1fr_auto]">
              <Input
                value={inviteEmail}
                onChange={(e) => setInviteEmail(e.target.value)}
                placeholder="alice@entreprise.com"
              />
              <Button
                disabled={!inviteEmail}
                onClick={() => {
                  const alternates = alternateEmails
                    .split(/[\n,;]+/)
                    .map((e) => e.trim())
                    .filter(Boolean)
                  void createInvite
                    .mutateAsync({
                      email: inviteEmail,
                      alternate_emails: alternates.length > 0 ? alternates : undefined,
                    })
                    .then((inv) => {
                      setInviteEmail("")
                      setAlternateEmails("")
                      if (inv.token) {
                        window.prompt(
                          "Lien de claim (copier)",
                          `${window.location.origin}/onboard/claim?token=${inv.token}`
                        )
                      }
                    })
                }}
              >
                Inviter
              </Button>
            </div>
            <div className="space-y-2">
              <Label htmlFor="alternate-emails">
                Emails alternatifs (SSO / alias, séparés par virgule ou ligne)
              </Label>
              <textarea
                id="alternate-emails"
                className="min-h-16 w-full rounded-md border bg-background px-3 py-2 text-sm"
                value={alternateEmails}
                onChange={(e) => setAlternateEmails(e.target.value)}
                placeholder="alice.smith@tenant.onmicrosoft.com"
              />
              <p className="text-xs text-muted-foreground">
                Adresses OIDC acceptées en plus de l&apos;email d&apos;invitation (UPN Microsoft,
                alias Gmail, etc.).
              </p>
            </div>
            <div className="space-y-2">
              <Label htmlFor="csv-emails">Import rapide (email seul, une ligne)</Label>
              <textarea
                id="csv-emails"
                className="min-h-24 w-full rounded-md border bg-background px-3 py-2 text-sm"
                value={csvEmails}
                onChange={(e) => setCsvEmails(e.target.value)}
                placeholder={"alice@entreprise.com\nbob@entreprise.com"}
              />
              <Button
                variant="outline"
                disabled={!csvEmails.trim()}
                onClick={() => {
                  const emails = csvEmails
                    .split(/\r?\n/)
                    .map((l) => l.trim())
                    .filter(Boolean)
                  void importInvites.mutateAsync(emails).then(() => setCsvEmails(""))
                }}
              >
                Importer les emails
              </Button>
            </div>

            <div className="space-y-3 rounded-md border border-dashed p-4">
              <div>
                <h4 className="text-sm font-medium">Pré-provision roster (CSV)</h4>
                <p className="text-xs text-muted-foreground">
                  Colonnes : <code>email</code> (requis), <code>display_name</code>,{" "}
                  <code>alternate_emails</code> (séparés par ;). En-tête optionnel.
                </p>
              </div>
              <textarea
                id="roster-csv"
                className="min-h-32 w-full rounded-md border bg-background px-3 py-2 font-mono text-xs"
                value={rosterCsv}
                onChange={(e) => setRosterCsv(e.target.value)}
                placeholder={
                  "email,display_name,alternate_emails\n" +
                  "alice@entreprise.com,Alice Dupont,alice.perso@gmail.com\n" +
                  "bob@entreprise.com,Bob Martin,"
                }
              />
              <Button
                disabled={!rosterCsv.trim() || importRoster.isPending}
                onClick={() => {
                  void importRoster
                    .mutateAsync(rosterCsv)
                    .then((result) => {
                      setRosterCsv("")
                      const errCount = result.errors?.length ?? 0
                      setRosterImportSummary(
                        `${result.created} créé(s), ${result.skipped_duplicates} doublon(s) ignoré(s)` +
                          (errCount > 0 ? `, ${errCount} erreur(s)` : "")
                      )
                    })
                    .catch((err: unknown) => {
                      setRosterImportSummary(
                        err instanceof ApiRequestError ? err.message : "Import roster échoué"
                      )
                    })
                }}
              >
                {importRoster.isPending ? "Import…" : "Importer le roster"}
              </Button>
              {rosterImportSummary && (
                <p className="text-sm text-muted-foreground">{rosterImportSummary}</p>
              )}
              {(rosterQuery.data?.roster?.length ?? 0) > 0 && (
                <div className="overflow-x-auto">
                  <table className="w-full text-left text-xs">
                    <thead>
                      <tr className="border-b text-muted-foreground">
                        <th className="py-1 pr-2 font-medium">Email</th>
                        <th className="py-1 pr-2 font-medium">Nom</th>
                        <th className="py-1 pr-2 font-medium">Statut</th>
                      </tr>
                    </thead>
                    <tbody>
                      {rosterQuery.data?.roster.map((entry) => (
                        <tr key={entry.id} className="border-b border-border/50">
                          <td className="py-1 pr-2">{entry.email}</td>
                          <td className="py-1 pr-2">{entry.display_name || "—"}</td>
                          <td className="py-1 pr-2">
                            <Badge variant={statusVariant(entry.status)}>{entry.status}</Badge>
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </div>
            <p className="text-xs text-muted-foreground">
              DNS : TXT <code>_ultisuite-verify.domaine</code>, MX vers Stalwart, SPF/DKIM/DMARC via
              Stalwart webadmin.
            </p>
          </div>
        </>
      )}
    </OrgSettingsSection>
  )
}

function SharedDrivesPanel({
  project,
  drives,
  loading,
  onModeChange,
  modePending,
  onApprove,
  onReject,
  actionPending,
}: {
  project: MigrationProject
  drives: MigrationSharedDrive[]
  loading: boolean
  onModeChange: (mode: "auto" | "manual") => void
  modePending: boolean
  onApprove: (driveId: string) => void
  onReject: (driveId: string) => void
  actionPending: boolean
}) {
  const mode = project.shared_drive_mode ?? "auto"
  const pending = drives.filter((d) => d.status === "pending")

  return (
    <div className="mt-8 space-y-4 rounded-lg border border-mail-border p-4">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h3 className="font-medium">Shared Drives Google</h3>
          <p className="text-xs text-muted-foreground">
            Import automatique ou approbation manuelle avant migration. Les fichiers partagés ne
            sont importés qu&apos;une fois par projet (déduplication).
          </p>
        </div>
        <Select
          value={mode}
          disabled={modePending}
          onValueChange={(v) => onModeChange(v as "auto" | "manual")}
        >
          <SelectTrigger className="w-[220px]">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="auto">Import auto</SelectItem>
            <SelectItem value="manual">Approbation manuelle</SelectItem>
          </SelectContent>
        </Select>
      </div>

      {loading && <p className="text-sm text-muted-foreground">Chargement des shared drives…</p>}

      {!loading && drives.length === 0 && (
        <p className="text-sm text-muted-foreground">
          Aucun shared drive découvert — lancez un job Drive utilisateur pour détecter les drives
          accessibles.
        </p>
      )}

      {mode === "manual" && pending.length > 0 && (
        <div className="space-y-2">
          <p className="text-sm font-medium">En attente d&apos;approbation ({pending.length})</p>
          <ul className="space-y-2">
            {pending.map((drive) => (
              <li
                key={drive.id}
                className="flex flex-wrap items-center justify-between gap-2 rounded-md border px-3 py-2 text-sm"
              >
                <div>
                  <span className="font-medium">{drive.name || drive.drive_id}</span>
                  <code className="ml-2 text-xs text-muted-foreground">{drive.drive_id}</code>
                </div>
                <div className="flex gap-2">
                  <Button
                    size="sm"
                    disabled={actionPending}
                    onClick={() => onApprove(drive.drive_id)}
                  >
                    Approuver
                  </Button>
                  <Button
                    size="sm"
                    variant="outline"
                    disabled={actionPending}
                    onClick={() => onReject(drive.drive_id)}
                  >
                    Rejeter
                  </Button>
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}

      {!loading && drives.length > 0 && (
        <div className="space-y-2">
          <p className="text-sm font-medium">Tous les shared drives ({drives.length})</p>
          <ul className="max-h-40 space-y-1 overflow-y-auto text-xs">
            {drives.map((drive) => (
              <li key={drive.id} className="flex items-center gap-2">
                <Badge
                  variant={
                    drive.status === "approved"
                      ? "default"
                      : drive.status === "rejected"
                        ? "destructive"
                        : "secondary"
                  }
                >
                  {drive.status}
                </Badge>
                <span>{drive.name || drive.drive_id}</span>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  )
}

function DNSReportCard({ report }: { report: DNSCheckReport }) {
  return (
    <div className="space-y-2 text-sm">
      {report.domain && (
        <p>
          Domaine : <span className="font-medium">{report.domain}</span>
        </p>
      )}
      <div className="flex flex-wrap gap-2">
        <Badge variant={report.txt_verified ? "default" : "destructive"}>
          TXT {report.txt_verified ? "OK" : "KO"}
        </Badge>
        <Badge variant={report.mx_verified ? "default" : "destructive"}>
          MX {report.mx_verified ? "OK" : "KO"}
        </Badge>
      </div>
      {report.txt_expected && (
        <p className="text-muted-foreground">
          Attendu TXT : <code>{report.txt_expected}</code>
        </p>
      )}
      {report.expected_mx && report.expected_mx.length > 0 && (
        <p className="text-muted-foreground">
          MX attendus : {report.expected_mx.join(", ")}
        </p>
      )}
      {report.mx_records && report.mx_records.length > 0 && (
        <p className="text-muted-foreground">MX live : {report.mx_records.join(", ")}</p>
      )}
      {report.warnings?.map((w) => (
        <p key={w} className="text-amber-700">
          {w}
        </p>
      ))}
      {report.errors?.map((e) => (
        <p key={e} className="text-destructive">
          {e}
        </p>
      ))}
    </div>
  )
}

function ProjectRow({
  project,
  selected,
  onSelect,
  onActivate,
  onCutover,
}: {
  project: MigrationProject
  selected: boolean
  onSelect: () => void
  onActivate: () => void
  onCutover: () => void
}) {
  return (
    <li
      className={`rounded-lg border p-4 ${selected ? "border-primary/50 bg-muted/30" : ""}`}
      onClick={onSelect}
      role="button"
      tabIndex={0}
      onKeyDown={(e) => {
        if (e.key === "Enter" || e.key === " ") onSelect()
      }}
    >
      <div className="flex flex-wrap items-center justify-between gap-2">
        <div>
          <p className="font-medium">{project.name}</p>
          <div className="mt-1 flex flex-wrap gap-2">
            <Badge variant="outline">{project.source_provider}</Badge>
            <Badge variant={statusVariant(project.status)}>{project.status}</Badge>
            <Badge variant="outline">{AUTH_MODE_LABELS[project.auth_mode] ?? project.auth_mode}</Badge>
            {project.source_provider === "microsoft" && (
              <Badge
                variant={
                  project.microsoft_admin_consent_at
                    ? "default"
                    : project.microsoft_admin_consent_error
                      ? "destructive"
                      : "outline"
                }
              >
                {project.microsoft_admin_consent_at
                  ? "MS consent OK"
                  : project.microsoft_admin_consent_error
                    ? "MS consent KO"
                    : "MS consent ?"}
              </Badge>
            )}
            {project.cutover_at && (
              <Badge variant="outline">
                cutover {new Date(project.cutover_at).toLocaleDateString()}
              </Badge>
            )}
            {project.cutover_dns && (
              <Badge
                variant={
                  project.cutover_dns.mx_verified && project.cutover_dns.txt_verified
                    ? "default"
                    : "destructive"
                }
              >
                DNS{" "}
                {project.cutover_dns.mx_verified && project.cutover_dns.txt_verified ? "OK" : "KO"}
              </Badge>
            )}
            {project.delta_mode && <Badge variant="secondary">delta</Badge>}
          </div>
        </div>
        <div className="flex gap-2" onClick={(e) => e.stopPropagation()}>
          <Button size="sm" variant="outline" onClick={onActivate}>
            Activer
          </Button>
          <Button size="sm" variant="secondary" onClick={onCutover}>
            Bascule MX
          </Button>
        </div>
      </div>
    </li>
  )
}

function JobsTable({
  jobs,
  loading,
  auditJobId,
  onAudit,
  onRetry,
  onResetCursor,
  retryPending,
  resetPending,
}: {
  jobs: MigrationJob[]
  loading: boolean
  auditJobId: string | null
  onAudit: (jobId: string) => void
  onRetry: (jobId: string) => void
  onResetCursor: (jobId: string) => void
  retryPending: boolean
  resetPending: boolean
}) {
  if (loading) {
    return <p className="text-sm text-muted-foreground">Chargement des jobs…</p>
  }
  if (jobs.length === 0) {
    return (
      <p className="text-sm text-muted-foreground">
        Aucun job — invitez des utilisateurs et demandez-leur de claim + OAuth.
      </p>
    )
  }

  return (
    <div className="overflow-x-auto">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b text-left text-muted-foreground">
            <th className="py-2 pr-3 font-medium">Utilisateur</th>
            <th className="py-2 pr-3 font-medium">Service</th>
            <th className="py-2 pr-3 font-medium">Statut</th>
            <th className="py-2 pr-3 font-medium">Importés</th>
            <th className="py-2 font-medium">Actions</th>
          </tr>
        </thead>
        <tbody>
          {jobs.map((job) => (
            <tr key={job.id} className="border-b last:border-0">
              <td className="py-2 pr-3">{job.user_email || job.user_id.slice(0, 8)}</td>
              <td className="py-2 pr-3">{SERVICE_LABELS[job.service] ?? job.service}</td>
              <td className="py-2 pr-3">
                <Badge variant={statusVariant(job.status)}>{job.status}</Badge>
                {job.stats_json?.rate_limited === true && (
                  <span className="ml-2 text-xs text-muted-foreground">(429)</span>
                )}
              </td>
              <td className="py-2 pr-3">{jobImportedCount(job)}</td>
              <td className="py-2">
                <div className="flex flex-wrap gap-2">
                  <Button
                    size="sm"
                    variant={auditJobId === job.id ? "secondary" : "outline"}
                    onClick={() => onAudit(job.id)}
                  >
                    Audit
                  </Button>
                  {job.status === "failed" && (
                    <Button
                      size="sm"
                      variant="outline"
                      disabled={retryPending}
                      onClick={() => onRetry(job.id)}
                    >
                      Relancer
                    </Button>
                  )}
                  {job.status !== "running" && (
                    <Button
                      size="sm"
                      variant="ghost"
                      disabled={resetPending}
                      onClick={() => onResetCursor(job.id)}
                    >
                      Réinitialiser
                    </Button>
                  )}
                </div>
                {job.error && (
                  <p className="mt-1 max-w-xs truncate text-xs text-destructive" title={job.error}>
                    {job.error}
                  </p>
                )}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

function JobAuditPanel({
  projectId,
  jobId,
  jobs,
}: {
  projectId: string
  jobId: string
  jobs: MigrationJob[]
}) {
  const job = jobs.find((j) => j.id === jobId)
  const summaryQuery = useMigrationJobAuditSummary(projectId, jobId)
  const failedQuery = useMigrationJobAudit(projectId, jobId, "failed")
  const skippedQuery = useMigrationJobAudit(projectId, jobId, "skipped")
  const [showSkipped, setShowSkipped] = useState(false)

  const summary = summaryQuery.data
  const failedItems = failedQuery.data?.items ?? []
  const skippedItems = skippedQuery.data?.items ?? []

  return (
    <div className="mt-4 space-y-3 rounded-lg border border-dashed p-4">
      <div className="flex flex-wrap items-center justify-between gap-2">
        <div>
          <h4 className="font-medium">Audit import — {job?.user_email ?? jobId.slice(0, 8)}</h4>
          <p className="text-xs text-muted-foreground">
            {SERVICE_LABELS[job?.service ?? ""] ?? job?.service} · statut job {job?.status ?? "—"}
          </p>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            disabled={!summary || summary.total === 0}
            onClick={() => void downloadMigrationJobAudit(projectId, jobId, "csv")}
          >
            <Download className="mr-2 size-4" />
            Export CSV
          </Button>
          <Button
            variant="outline"
            size="sm"
            disabled={!summary || summary.total === 0}
            onClick={() => void downloadMigrationJobAudit(projectId, jobId, "ndjson")}
          >
            <Download className="mr-2 size-4" />
            Export NDJSON
          </Button>
          {summaryQuery.isLoading && (
            <span className="text-xs text-muted-foreground">Chargement…</span>
          )}
        </div>
      </div>

      {summary && (
        <div className="flex flex-wrap gap-2">
          <Badge variant="default">{summary.imported} importés</Badge>
          <Badge variant={summary.failed > 0 ? "destructive" : "outline"}>
            {summary.failed} échecs
          </Badge>
          <Badge variant={summary.skipped > 0 ? "secondary" : "outline"}>
            {summary.skipped} ignorés
          </Badge>
          <Badge variant="outline">{summary.total} total</Badge>
        </div>
      )}

      {summary && summary.total === 0 && (
        <p className="text-sm text-muted-foreground">
          Aucun élément enregistré — le job n&apos;a pas encore traité d&apos;items ou la migration
          date d&apos;avant l&apos;audit.
        </p>
      )}

      {failedItems.length > 0 && (
        <AuditItemList title="Échecs" items={failedItems} variant="destructive" />
      )}

      {summary && summary.skipped > 0 && (
        <div className="space-y-2">
          <Button size="sm" variant="ghost" onClick={() => setShowSkipped((v) => !v)}>
            {showSkipped ? "Masquer" : "Afficher"} les ignorés ({summary.skipped})
          </Button>
          {showSkipped && skippedItems.length > 0 && (
            <AuditItemList title="Ignorés" items={skippedItems} variant="secondary" />
          )}
        </div>
      )}

      {summary && summary.failed === 0 && summary.skipped === 0 && summary.total > 0 && (
        <p className="text-sm text-green-700">Tous les éléments suivis ont été importés avec succès.</p>
      )}
    </div>
  )
}

function AuditItemList({
  title,
  items,
  variant,
}: {
  title: string
  items: MigrationJobAuditItem[]
  variant: "destructive" | "secondary"
}) {
  return (
    <div className="space-y-2">
      <p className="text-sm font-medium">{title}</p>
      <ul className="max-h-48 space-y-1 overflow-y-auto text-xs">
        {items.map((item) => (
          <li key={item.source_id} className="rounded border px-2 py-1.5">
            <div className="flex flex-wrap items-center gap-2">
              <Badge variant={variant}>{item.status}</Badge>
              <code className="truncate">{item.source_id}</code>
              {item.rel_path && (
                <span className="truncate text-muted-foreground">{item.rel_path}</span>
              )}
            </div>
            {item.reason && (
              <p className="mt-1 text-destructive" title={item.reason}>
                {item.reason}
              </p>
            )}
          </li>
        ))}
      </ul>
    </div>
  )
}
