"use client"

import { useEffect, useMemo, useState } from "react"
import {
  Copy,
  Loader2,
  Plus,
  RefreshCw,
  TestTube2,
  Trash2,
} from "lucide-react"
import { guideForProvider } from "@/components/admin/settings/guides/identity-provider-guides"
import { TechBrandSelectLabel } from "@/components/admin/settings/tech-brand-select-label"
import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store"
import type {
  IdentityProvider,
  IdentityProviderType,
  OAuthProviderPreset,
} from "@/lib/admin-settings/org-settings-types"
import {
  useIdentityProviderRedirectURI,
  useSyncIdentityProvider,
  useTestIdentityProvider,
} from "@/lib/api/hooks/use-identity-provider-actions"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import {
  Sheet,
  SheetContent,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet"
import { Switch } from "@/components/ui/switch"
import { Textarea } from "@/components/ui/textarea"
import { toast } from "sonner"

const OAUTH_PRESET_LABELS: Record<OAuthProviderPreset, string> = {
  google: "Google",
  github: "GitHub",
  linkedin: "LinkedIn",
  microsoft: "Microsoft",
  custom: "Autre / custom",
}

function splitList(value: string): string[] {
  return value
    .split(/[\n,]/)
    .map((item) => item.trim())
    .filter(Boolean)
}

function joinList(values: string[] | undefined): string {
  return (values ?? []).join("\n")
}

function slugify(value: string): string {
  return value
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
}

function emptyProvider(type: IdentityProviderType): IdentityProvider {
  const id = crypto.randomUUID()
  const base = {
    id,
    name: "",
    slug: "",
    type,
    enabled: true,
    sync_status: "pending" as const,
    allowed_email_domains: [],
    allowed_identities: [],
    allowed_organizations: [],
    default_groups: [],
  }
  if (type === "oauth") {
    return {
      ...base,
      oauth: {
        provider: "google",
        client_id: "",
        client_secret: "",
        scopes: "openid email profile",
      },
    }
  }
  if (type === "saml") {
    return { ...base, saml: { metadata_url: "", entity_id: "", sso_url: "" } }
  }
  return {
    ...base,
    ldap: {
      server_uri: "",
      bind_dn: "",
      bind_password: "",
      base_dn: "",
      user_filter: "",
      start_tls: true,
      sync_users: false,
    },
  }
}

function syncBadge(status: IdentityProvider["sync_status"]) {
  switch (status) {
    case "synced":
      return <Badge variant="secondary">Synchronisé</Badge>
    case "error":
      return <Badge variant="destructive">Erreur sync</Badge>
    default:
      return <Badge variant="outline">En attente</Badge>
  }
}

export function IdentityProvidersPanel({
  onRegisterBeforeSave,
}: {
  onRegisterBeforeSave?: (fn: (() => void) | null) => void
}) {
  const identityProviders = useOrgSettingsStore((s) => s.identityProviders)
  const setIdentityProviders = useOrgSettingsStore((s) => s.setIdentityProviders)
  const meta = useOrgSettingsStore((s) => s.meta)
  const [draft, setDraft] = useState(identityProviders)
  const [addOpen, setAddOpen] = useState(false)
  const [editIndex, setEditIndex] = useState<number | null>(null)
  const [newType, setNewType] = useState<IdentityProviderType>("oauth")
  const testMutation = useTestIdentityProvider()
  const syncMutation = useSyncIdentityProvider()
  const redirectMutation = useIdentityProviderRedirectURI()

  useEffect(() => {
    setDraft(identityProviders)
  }, [identityProviders])

  const redirectTemplate =
    meta?.effective.identity_providers?.oauth_redirect_template ??
    "http://localhost/auth/source/oauth/callback/{slug}/"

  const editingProvider = editIndex != null ? draft.providers[editIndex] : null

  const guide = useMemo(() => {
    if (!editingProvider) return null
    return guideForProvider(
      editingProvider.type,
      editingProvider.oauth?.provider
    )
  }, [editingProvider])

  function updateProvider(index: number, patch: Partial<IdentityProvider>) {
    setDraft((prev) => {
      const providers = [...prev.providers]
      providers[index] = { ...providers[index], ...patch }
      return { ...prev, providers }
    })
  }

  function addProvider(type: IdentityProviderType) {
    const provider = emptyProvider(type)
    setDraft((prev) => ({
      ...prev,
      providers: [...prev.providers, provider],
    }))
    setAddOpen(false)
    setEditIndex(draft.providers.length)
  }

  function removeProvider(index: number) {
    setDraft((prev) => ({
      ...prev,
      providers: prev.providers.filter((_, i) => i !== index),
    }))
    if (editIndex === index) setEditIndex(null)
  }

  function providerSecrets(provider: IdentityProvider): Record<string, { configured?: boolean }> {
    const idpSecrets = meta?.secrets?.identity_providers
    if (!idpSecrets || typeof idpSecrets !== "object") return {}
    const entry = (idpSecrets as Record<string, Record<string, { configured?: boolean }>>)[
      provider.id
    ]
    return entry ?? {}
  }

  async function handleTest(provider: IdentityProvider) {
    try {
      await testMutation.mutateAsync(provider.id)
      toast.success("Configuration valide")
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "Test échoué")
    }
  }

  async function handleSync(provider: IdentityProvider) {
    try {
      await syncMutation.mutateAsync(provider.id)
      toast.success("Synchronisation Authentik lancée")
    } catch {
      toast.error("Synchronisation échouée")
    }
  }

  async function copyRedirect(slug: string) {
    try {
      const res = await redirectMutation.mutateAsync(slug)
      await navigator.clipboard.writeText(res.redirect_uri)
      toast.success("URI de redirection copiée")
    } catch {
      const fallback = redirectTemplate.replace("{slug}", slug)
      await navigator.clipboard.writeText(fallback)
      toast.success("URI de redirection copiée")
    }
  }

  useEffect(() => {
    onRegisterBeforeSave?.(() => setIdentityProviders(draft))
    return () => onRegisterBeforeSave?.(null)
  }, [draft, onRegisterBeforeSave, setIdentityProviders])

  return (
    <>
      <label className="flex items-center justify-between gap-4 rounded-lg border p-4">
        <div>
          <p className="text-sm font-medium">Inscription self-service Authentik</p>
          <p className="text-xs text-muted-foreground">
            Flow ulti-enrollment : autoriser la création de compte locale en parallèle du SSO entreprise.
          </p>
        </div>
        <Switch
          checked={draft.allow_self_enrollment}
          onCheckedChange={(allow_self_enrollment) =>
            setDraft((prev) => ({ ...prev, allow_self_enrollment }))
          }
        />
      </label>

      <div className="flex items-center justify-between">
        <Label>Fournisseurs configurés</Label>
        <Button variant="outline" size="sm" onClick={() => setAddOpen(true)}>
          <Plus className="mr-2 size-4" />
          Ajouter
        </Button>
      </div>

      {draft.providers.length === 0 ? (
        <p className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground">
          Aucun fournisseur. Ajoutez Google Workspace, Azure AD SAML, LDAP AD ou un OAuth custom.
        </p>
      ) : (
        <div className="grid gap-3">
          {draft.providers.map((provider, index) => (
            <div
              key={provider.id}
              className="flex flex-wrap items-center justify-between gap-3 rounded-lg border p-4"
            >
              <div className="space-y-1">
                <div className="flex flex-wrap items-center gap-2">
                  <span className="text-sm font-medium">
                    {provider.name || provider.slug || "Nouveau fournisseur"}
                  </span>
                  <Badge variant="outline">{provider.type.toUpperCase()}</Badge>
                  {syncBadge(provider.sync_status)}
                </div>
                <p className="text-xs text-muted-foreground">
                  Slug : {provider.slug || "—"}
                  {provider.sync_error ? ` · ${provider.sync_error}` : ""}
                </p>
              </div>
              <div className="flex flex-wrap items-center gap-2">
                <Switch
                  checked={provider.enabled}
                  onCheckedChange={(enabled) => updateProvider(index, { enabled })}
                />
                <Button variant="outline" size="sm" onClick={() => setEditIndex(index)}>
                  Modifier
                </Button>
                <Button
                  variant="outline"
                  size="icon"
                  disabled={testMutation.isPending}
                  onClick={() => handleTest(provider)}
                >
                  <TestTube2 className="size-4" />
                </Button>
                <Button
                  variant="outline"
                  size="icon"
                  disabled={syncMutation.isPending}
                  onClick={() => handleSync(provider)}
                >
                  {syncMutation.isPending ? (
                    <Loader2 className="size-4 animate-spin" />
                  ) : (
                    <RefreshCw className="size-4" />
                  )}
                </Button>
                <Button variant="ghost" size="icon" onClick={() => removeProvider(index)}>
                  <Trash2 className="size-4" />
                </Button>
              </div>
            </div>
          ))}
        </div>
      )}

      <Dialog open={addOpen} onOpenChange={setAddOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Ajouter un fournisseur</DialogTitle>
          </DialogHeader>
          <div className="space-y-4">
            <div>
              <Label>Type</Label>
              <Select
                value={newType}
                onValueChange={(value) => setNewType(value as IdentityProviderType)}
              >
                <SelectTrigger className="mt-1 h-9">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="oauth">
                    <TechBrandSelectLabel brand="oauth">
                      OAuth (Google, GitHub, LinkedIn…)
                    </TechBrandSelectLabel>
                  </SelectItem>
                  <SelectItem value="saml">
                    <TechBrandSelectLabel brand="saml">
                      SAML (Azure AD, Okta…)
                    </TechBrandSelectLabel>
                  </SelectItem>
                  <SelectItem value="ldap">
                    <TechBrandSelectLabel brand="ldap">
                      LDAP / Active Directory
                    </TechBrandSelectLabel>
                  </SelectItem>
                </SelectContent>
              </Select>
            </div>
            <Button onClick={() => addProvider(newType)}>Créer</Button>
          </div>
        </DialogContent>
      </Dialog>

      <Sheet open={editIndex != null} onOpenChange={(open) => !open && setEditIndex(null)}>
        <SheetContent className="flex w-full flex-col gap-0 overflow-y-auto p-0 sm:max-w-2xl">
          {editingProvider && editIndex != null ? (
            <>
              <SheetHeader className="border-b px-6 py-5">
                <SheetTitle>Configurer le fournisseur</SheetTitle>
              </SheetHeader>
              <div className="grid gap-6 px-6 py-6 lg:grid-cols-[1fr_240px]">
                <div className="space-y-4">
                  <div className="grid gap-4 sm:grid-cols-2">
                    <div>
                      <Label>Nom</Label>
                      <Input
                        className="mt-1 h-9"
                        value={editingProvider.name}
                        onChange={(e) => {
                          const name = e.target.value
                          updateProvider(editIndex, {
                            name,
                            slug: editingProvider.slug || slugify(name),
                          })
                        }}
                      />
                    </div>
                    <div>
                      <Label>Slug Authentik</Label>
                      <Input
                        className="mt-1 h-9"
                        value={editingProvider.slug}
                        onChange={(e) =>
                          updateProvider(editIndex, { slug: slugify(e.target.value) })
                        }
                      />
                    </div>
                  </div>

                  {editingProvider.type === "oauth" ? (
                    <div className="space-y-4 rounded-lg border p-4">
                      <div>
                        <Label>Présélection</Label>
                        <Select
                          value={editingProvider.oauth?.provider ?? "google"}
                          onValueChange={(provider) =>
                            updateProvider(editIndex, {
                              oauth: {
                                ...(editingProvider.oauth ?? {
                                  client_id: "",
                                  client_secret: "",
                                  scopes: "openid email profile",
                                  provider: "google" as OAuthProviderPreset,
                                }),
                                provider: provider as OAuthProviderPreset,
                              },
                            })
                          }
                        >
                          <SelectTrigger className="mt-1 h-9">
                            <SelectValue>
                              {editingProvider.oauth?.provider ? (
                                <TechBrandSelectLabel brand={editingProvider.oauth.provider}>
                                  {OAUTH_PRESET_LABELS[editingProvider.oauth.provider]}
                                </TechBrandSelectLabel>
                              ) : null}
                            </SelectValue>
                          </SelectTrigger>
                          <SelectContent>
                            <SelectItem value="google">
                              <TechBrandSelectLabel brand="google">Google</TechBrandSelectLabel>
                            </SelectItem>
                            <SelectItem value="github">
                              <TechBrandSelectLabel brand="github">GitHub</TechBrandSelectLabel>
                            </SelectItem>
                            <SelectItem value="linkedin">
                              <TechBrandSelectLabel brand="linkedin">LinkedIn</TechBrandSelectLabel>
                            </SelectItem>
                            <SelectItem value="microsoft">
                              <TechBrandSelectLabel brand="microsoft">Microsoft</TechBrandSelectLabel>
                            </SelectItem>
                            <SelectItem value="custom">
                              <TechBrandSelectLabel brand="custom">Autre / custom</TechBrandSelectLabel>
                            </SelectItem>
                          </SelectContent>
                        </Select>
                      </div>
                      <div>
                        <Label>Client ID</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.oauth?.client_id ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              oauth: { ...editingProvider.oauth!, client_id: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Client Secret</Label>
                        <Input
                          className="mt-1 h-9"
                          type="password"
                          placeholder={
                            providerSecrets(editingProvider).oauth_client_secret?.configured
                              ? "Laisser vide pour conserver"
                              : "Secret OAuth"
                          }
                          value={editingProvider.oauth?.client_secret ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              oauth: {
                                ...editingProvider.oauth!,
                                client_secret: e.target.value,
                              },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Scopes</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.oauth?.scopes ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              oauth: { ...editingProvider.oauth!, scopes: e.target.value },
                            })
                          }
                        />
                      </div>
                      {editingProvider.oauth?.provider === "custom" ? (
                        <>
                          <div>
                            <Label>Authorization URL</Label>
                            <Input
                              className="mt-1 h-9"
                              value={editingProvider.oauth.authorization_url ?? ""}
                              onChange={(e) =>
                                updateProvider(editIndex, {
                                  oauth: {
                                    ...editingProvider.oauth!,
                                    authorization_url: e.target.value,
                                  },
                                })
                              }
                            />
                          </div>
                          <div>
                            <Label>Token URL</Label>
                            <Input
                              className="mt-1 h-9"
                              value={editingProvider.oauth.token_url ?? ""}
                              onChange={(e) =>
                                updateProvider(editIndex, {
                                  oauth: {
                                    ...editingProvider.oauth!,
                                    token_url: e.target.value,
                                  },
                                })
                              }
                            />
                          </div>
                          <div>
                            <Label>Profile URL</Label>
                            <Input
                              className="mt-1 h-9"
                              value={editingProvider.oauth.profile_url ?? ""}
                              onChange={(e) =>
                                updateProvider(editIndex, {
                                  oauth: {
                                    ...editingProvider.oauth!,
                                    profile_url: e.target.value,
                                  },
                                })
                              }
                            />
                          </div>
                        </>
                      ) : null}
                      <div>
                        <Label>URI de redirection</Label>
                        <div className="mt-1 flex gap-2">
                          <Input
                            className="h-9"
                            readOnly
                            value={redirectTemplate.replace(
                              "{slug}",
                              editingProvider.slug || "votre-slug"
                            )}
                          />
                          <Button
                            type="button"
                            variant="outline"
                            size="icon"
                            onClick={() => copyRedirect(editingProvider.slug)}
                          >
                            <Copy className="size-4" />
                          </Button>
                        </div>
                      </div>
                    </div>
                  ) : null}

                  {editingProvider.type === "saml" ? (
                    <div className="space-y-4 rounded-lg border p-4">
                      <div>
                        <Label>Metadata URL</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.saml?.metadata_url ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              saml: { ...editingProvider.saml!, metadata_url: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Entity ID / Issuer</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.saml?.entity_id ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              saml: { ...editingProvider.saml!, entity_id: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>SSO URL</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.saml?.sso_url ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              saml: { ...editingProvider.saml!, sso_url: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Certificat signing (PEM)</Label>
                        <Textarea
                          className="mt-1 min-h-24 font-mono text-xs"
                          placeholder={
                            providerSecrets(editingProvider).saml_signing_cert?.configured
                              ? "Laisser vide pour conserver"
                              : "-----BEGIN CERTIFICATE-----"
                          }
                          value={editingProvider.saml?.signing_cert ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              saml: {
                                ...editingProvider.saml!,
                                signing_cert: e.target.value,
                              },
                            })
                          }
                        />
                      </div>
                    </div>
                  ) : null}

                  {editingProvider.type === "ldap" ? (
                    <div className="space-y-4 rounded-lg border p-4">
                      <div>
                        <Label>Server URI</Label>
                        <Input
                          className="mt-1 h-9"
                          placeholder="ldaps://ad.company.com:636"
                          value={editingProvider.ldap?.server_uri ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              ldap: { ...editingProvider.ldap!, server_uri: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Bind DN</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.ldap?.bind_dn ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              ldap: { ...editingProvider.ldap!, bind_dn: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Bind password</Label>
                        <Input
                          className="mt-1 h-9"
                          type="password"
                          placeholder={
                            providerSecrets(editingProvider).ldap_bind_password?.configured
                              ? "Laisser vide pour conserver"
                              : "Mot de passe LDAP"
                          }
                          value={editingProvider.ldap?.bind_password ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              ldap: {
                                ...editingProvider.ldap!,
                                bind_password: e.target.value,
                              },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Base DN</Label>
                        <Input
                          className="mt-1 h-9"
                          value={editingProvider.ldap?.base_dn ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              ldap: { ...editingProvider.ldap!, base_dn: e.target.value },
                            })
                          }
                        />
                      </div>
                      <div>
                        <Label>Filtre utilisateur</Label>
                        <Input
                          className="mt-1 h-9"
                          placeholder="(sAMAccountName=%(user)s)"
                          value={editingProvider.ldap?.user_filter ?? ""}
                          onChange={(e) =>
                            updateProvider(editIndex, {
                              ldap: {
                                ...editingProvider.ldap!,
                                user_filter: e.target.value,
                              },
                            })
                          }
                        />
                      </div>
                      <label className="flex items-center justify-between gap-4 rounded-lg border p-3">
                        <span className="text-sm">StartTLS</span>
                        <Switch
                          checked={editingProvider.ldap?.start_tls ?? true}
                          onCheckedChange={(start_tls) =>
                            updateProvider(editIndex, {
                              ldap: { ...editingProvider.ldap!, start_tls },
                            })
                          }
                        />
                      </label>
                      <label className="flex items-center justify-between gap-4 rounded-lg border p-3">
                        <span className="text-sm">Synchroniser les utilisateurs LDAP</span>
                        <Switch
                          checked={editingProvider.ldap?.sync_users ?? false}
                          onCheckedChange={(sync_users) =>
                            updateProvider(editIndex, {
                              ldap: { ...editingProvider.ldap!, sync_users },
                            })
                          }
                        />
                      </label>
                    </div>
                  ) : null}

                  <div className="space-y-3 rounded-lg border p-4">
                    <p className="text-sm font-medium">Restrictions d&apos;accès</p>
                    <div>
                      <Label>Domaines email autorisés</Label>
                      <Textarea
                        className="mt-1 min-h-20"
                        placeholder="company.com&#10;subsidiary.fr"
                        value={joinList(editingProvider.allowed_email_domains)}
                        onChange={(e) =>
                          updateProvider(editIndex, {
                            allowed_email_domains: splitList(e.target.value),
                          })
                        }
                      />
                    </div>
                    <div>
                      <Label>Identités autorisées (emails)</Label>
                      <Textarea
                        className="mt-1 min-h-20"
                        placeholder="admin@company.com"
                        value={joinList(editingProvider.allowed_identities)}
                        onChange={(e) =>
                          updateProvider(editIndex, {
                            allowed_identities: splitList(e.target.value),
                          })
                        }
                      />
                    </div>
                    <div>
                      <Label>Organisations autorisées</Label>
                      <Textarea
                        className="mt-1 min-h-20"
                        placeholder="tenant-id Azure, domaine Google hd, org GitHub…"
                        value={joinList(editingProvider.allowed_organizations)}
                        onChange={(e) =>
                          updateProvider(editIndex, {
                            allowed_organizations: splitList(e.target.value),
                          })
                        }
                      />
                    </div>
                    <div>
                      <Label>Groupes Authentik par défaut</Label>
                      <Input
                        className="mt-1 h-9"
                        placeholder="ulti-users, ulti-admins"
                        value={joinList(editingProvider.default_groups).replace(/\n/g, ", ")}
                        onChange={(e) =>
                          updateProvider(editIndex, {
                            default_groups: splitList(e.target.value.replace(/,/g, "\n")),
                          })
                        }
                      />
                    </div>
                  </div>
                </div>

                {guide ? (
                  <aside className="rounded-lg border bg-muted/30 p-4">
                    <p className="text-sm font-medium">{guide.title}</p>
                    <ol className="mt-3 list-decimal space-y-2 pl-4 text-xs text-muted-foreground">
                      {guide.steps.map((step) => (
                        <li key={step}>{step}</li>
                      ))}
                    </ol>
                  </aside>
                ) : null}
              </div>
            </>
          ) : null}
        </SheetContent>
      </Sheet>
    </>
  )
}
