'use client'

import * as Tabs from '@radix-ui/react-tabs'
import {
  Bot,
  Eye,
  EyeOff,
  Loader2,
  AlertTriangle,
  Download,
  CheckCircle2,
  ArrowUpCircle,
  ExternalLink,
  RefreshCw,
  GitPullRequest,
  Layers,
  Users as UsersIcon,
  KeyRound,
} from 'lucide-react'
import { useState, useEffect, useCallback, useMemo } from 'react'
import { toast } from 'sonner'
import { useApiData } from '../lib/useApiData.js'
import { cmsApi } from '../lib/api.js'
import { RelationshipField } from '../fields/RelationshipField.js'
import { GeneralSettingsTab } from './settings/GeneralSettingsTab.js'
import { SeoSettingsTab } from './settings/SeoSettingsTab.js'
import { AISettingsTab } from './settings/AISettingsTab.js'
import { AppearanceTab } from './settings/AppearanceTab.js'
import { SecurityTab } from './settings/SecurityTab.js'
import { SettingsCard } from './settings/components.js'
import { Users as UsersView } from './Users.js'
import { ApiKeys as ApiKeysView } from './ApiKeys.js'

export interface SettingsProps {
  onNavigate?: (path: string) => void
  config?: any
  /** Current admin session — used to gate editing on role. */
  session?: any
  /** Initial tab when arriving without a `?tab=` query param (e.g. via the
   * legacy `/users` or `/api-keys` routes). */
  initialTab?: string
}

/**
 * Tabs that persist through the shared footer's `handleSave` (which writes
 * `defaultLayout` into the settings global). Every other tab owns its own
 * saving, so the footer must NOT render there — otherwise it shows a
 * "Settings saved successfully!" toast while persisting nothing relevant.
 * This is an allowlist on purpose: new tabs default to self-managed.
 */
const GLOBAL_SAVE_TABS = new Set(['layout'])

function readSettingsTabFromUrl(): string | null {
  if (typeof window === 'undefined') return null
  return new URLSearchParams(window.location.search).get('tab')
}

export function Settings({
  config,
  onNavigate,
  session,
  initialTab = 'general',
}: SettingsProps = {}) {
  const { data, loading, error, refetch } = useApiData<any>('/globals/settings')

  const [activeTab, setActiveTab] = useState<string>(() => readSettingsTabFromUrl() ?? initialTab)
  const [saving, setSaving] = useState(false)

  // Layout defaults
  const [defaultLayout, setDefaultLayout] = useState<Record<string, string>>({})
  const layoutConfig = config?.layout
  const layoutRegions: Array<{ name: string; collection: string; label: string }> =
    layoutConfig?.regions
      ? Object.entries(layoutConfig.regions).map(([name, region]: [string, any]) => ({
          name,
          collection: region.collection,
          label: region.label ?? name.charAt(0).toUpperCase() + name.slice(1),
        }))
      : []
  const hasLayoutRegions = layoutRegions.length > 0

  // Valid tab ids, with `layout` only available when the project configures
  // layout regions. Used to normalise deep links and keep the URL honest.
  const availableTabs = useMemo(
    () =>
      [
        'general',
        'appearance',
        ...(hasLayoutRegions ? ['layout'] : []),
        'security',
        'users',
        'api-keys',
        'seo',
        'ai',
        'updates',
      ] as const,
    [hasLayoutRegions],
  )
  const normalizeTab = useCallback(
    (tab: string | null | undefined): string =>
      tab && (availableTabs as readonly string[]).includes(tab) ? tab : 'general',
    [availableTabs],
  )

  // Drive the active tab from the `?tab=` query param so tabs are deep-linkable
  // and survive browser back/forward (the legacy /users and /api-keys routes
  // land here via `initialTab`).
  useEffect(() => {
    function sync() {
      setActiveTab(normalizeTab(readSettingsTabFromUrl() ?? initialTab))
    }
    sync()
    window.addEventListener('popstate', sync)
    return () => window.removeEventListener('popstate', sync)
  }, [normalizeTab, initialTab])

  const changeTab = useCallback(
    (tab: string) => {
      const next = normalizeTab(tab)
      setActiveTab(next)
      onNavigate?.(`/settings?tab=${next}`)
    },
    [normalizeTab, onNavigate],
  )

  useEffect(() => {
    if (data) {
      if (data.defaultLayout && typeof data.defaultLayout === 'object') {
        setDefaultLayout(data.defaultLayout)
      }
    }
  }, [data])

  const handleSave = async () => {
    setSaving(true)
    const layoutPayload = Object.keys(defaultLayout).length > 0 ? { defaultLayout } : {}
    // Read-modify-write: the General tab owns site info / SEO defaults in the
    // same global blob, so merge against a fresh fetch instead of overwriting.
    const current = await cmsApi<Record<string, unknown>>('/globals/settings')
    const res = await cmsApi('/globals/settings', {
      method: 'PUT',
      body: JSON.stringify({
        ...(current.data ?? {}),
        ...layoutPayload,
      }),
    })
    setSaving(false)
    if (res.error) {
      toast.error(res.error)
    } else {
      toast.success('Settings saved successfully!')
    }
  }

  const tabTriggerClass =
    'text-muted-foreground hover:text-foreground data-[state=active]:border-brand data-[state=active]:text-brand px-4 py-2 text-base font-medium transition-colors data-[state=active]:border-b-2'

  if (loading) {
    return (
      <div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
        <Loader2 className="h-6 w-6 animate-spin text-blue-600" />
      </div>
    )
  }

  return (
    <div className="p-3 pr-6 sm:p-4 sm:pr-8">
      {error && (
        <div
          role="alert"
          className="border-destructive/30 bg-destructive/10 text-destructive mb-4 flex items-center gap-3 rounded-lg border p-3 text-sm"
        >
          <AlertTriangle size={20} className="shrink-0" aria-hidden="true" />
          <span className="flex-1">{error}</span>
          <button
            onClick={refetch}
            className="border-destructive/40 rounded-md border px-3 py-1 transition-colors hover:opacity-80"
          >
            Retry
          </button>
        </div>
      )}

      <div className="mb-4">
        <h1 className="text-foreground mb-1 text-2xl font-medium">Settings</h1>
        <p className="text-muted-foreground text-sm">Manage your CMS configuration</p>
      </div>

      <Tabs.Root value={activeTab} onValueChange={changeTab}>
        <Tabs.List className="border-border mb-4 flex gap-1 overflow-x-auto border-b">
          <Tabs.Trigger value="general" className={tabTriggerClass}>
            General
          </Tabs.Trigger>
          <Tabs.Trigger value="appearance" className={tabTriggerClass}>
            Appearance
          </Tabs.Trigger>
          {hasLayoutRegions && (
            <Tabs.Trigger value="layout" className={tabTriggerClass}>
              <span className="flex items-center gap-1.5">
                <Layers className="h-4 w-4" />
                Layout
              </span>
            </Tabs.Trigger>
          )}
          <Tabs.Trigger value="security" className={tabTriggerClass}>
            Security
          </Tabs.Trigger>
          <Tabs.Trigger value="users" className={tabTriggerClass}>
            <span className="flex items-center gap-1.5">
              <UsersIcon className="h-4 w-4" />
              Users
            </span>
          </Tabs.Trigger>
          <Tabs.Trigger value="api-keys" className={tabTriggerClass}>
            <span className="flex items-center gap-1.5">
              <KeyRound className="h-4 w-4" />
              API Keys
            </span>
          </Tabs.Trigger>
          <Tabs.Trigger value="seo" className={tabTriggerClass}>
            SEO
          </Tabs.Trigger>
          <Tabs.Trigger value="ai" className={tabTriggerClass}>
            <span className="flex items-center gap-1.5">
              <Bot className="h-4 w-4" />
              AI
            </span>
          </Tabs.Trigger>
          <Tabs.Trigger value="updates" className={tabTriggerClass}>
            <span className="flex items-center gap-1.5">
              <Download className="h-4 w-4" />
              Updates
            </span>
          </Tabs.Trigger>
        </Tabs.List>

        <Tabs.Content value="general">
          <GeneralSettingsTab onNavigate={onNavigate} role={session?.user?.role} />
        </Tabs.Content>

        <Tabs.Content value="appearance" className="space-y-4">
          <AppearanceTab role={session?.user?.role} config={config} />
        </Tabs.Content>

        {hasLayoutRegions && (
          <Tabs.Content value="layout" className="space-y-4">
            <SettingsCard
              title="Default Layout Variants"
              description="Select the default header, footer, and other layout variants used site-wide. Pages can override these individually or inherit from parent pages."
            >
              <div className="space-y-4">
                {layoutRegions.map((region) => (
                  <RelationshipField
                    key={region.name}
                    label={`Default ${region.label}`}
                    value={defaultLayout[region.name] ?? ''}
                    onChange={(val) => {
                      setDefaultLayout((prev) => {
                        const next = { ...prev }
                        if (val && typeof val === 'string') {
                          next[region.name] = val
                        } else {
                          delete next[region.name]
                        }
                        return next
                      })
                    }}
                    relationTo={region.collection}
                    helpText={`The ${region.label.toLowerCase()} variant used when no page in the ancestor chain specifies one`}
                  />
                ))}
              </div>
            </SettingsCard>
            <SettingsCard title="How Layout Inheritance Works">
              <ul className="text-muted-foreground space-y-1.5 text-sm">
                <li className="flex items-start gap-2">
                  <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
                    1
                  </span>
                  <span>
                    Each page can assign specific layout variants (header, footer, etc.) from the
                    document editor.
                  </span>
                </li>
                <li className="flex items-start gap-2">
                  <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
                    2
                  </span>
                  <span>
                    Child pages automatically inherit their parent&apos;s layout. For example,{' '}
                    <code className="bg-muted rounded px-1 font-mono">
                      /hampton-roads/thank-you
                    </code>{' '}
                    inherits from{' '}
                    <code className="bg-muted rounded px-1 font-mono">/hampton-roads</code>.
                  </span>
                </li>
                <li className="flex items-start gap-2">
                  <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
                    3
                  </span>
                  <span>
                    If no page in the ancestor chain sets a variant, the defaults configured above
                    are used.
                  </span>
                </li>
              </ul>
            </SettingsCard>
          </Tabs.Content>
        )}

        <Tabs.Content value="security" className="space-y-4">
          <SecurityTab role={session?.user?.role} onNavigate={onNavigate} />
        </Tabs.Content>

        <Tabs.Content value="seo" className="space-y-4">
          <SeoSettingsTab onNavigate={onNavigate} role={session?.user?.role} />
        </Tabs.Content>

        <Tabs.Content value="ai" className="space-y-4">
          <AISettingsTab role={session?.user?.role} />
        </Tabs.Content>

        <Tabs.Content value="users">
          <UsersView onNavigate={onNavigate} embedded />
        </Tabs.Content>

        <Tabs.Content value="api-keys">
          <ApiKeysView onNavigate={onNavigate} embedded />
        </Tabs.Content>

        <Tabs.Content value="updates" className="space-y-4">
          <UpdatesPanel />
        </Tabs.Content>
      </Tabs.Root>

      {GLOBAL_SAVE_TABS.has(activeTab) && (
        <div className="mt-6 flex justify-end">
          <button
            type="button"
            onClick={handleSave}
            disabled={saving}
            className="rounded-lg bg-blue-600 px-6 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
          >
            {saving ? 'Saving...' : 'Save Changes'}
          </button>
        </div>
      )}
    </div>
  )
}

// ---------------------------------------------------------------------------
// Updates Panel
// ---------------------------------------------------------------------------

interface UpdateInfo {
  current: string
  latest: string
  updateAvailable: boolean
  severity?: 'patch' | 'minor' | 'major'
  releaseDate?: string
  changelog?: Array<{ version: string; date: string; summary: string }>
  updateCommand?: string
  hasGithubToken?: boolean
  githubRepo?: string
}

function UpdatesPanel() {
  const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null)
  const [checking, setChecking] = useState(false)
  const [checkError, setCheckError] = useState('')
  const [applying, setApplying] = useState(false)
  const [prResult, setPrResult] = useState<{ prUrl: string; prNumber: number } | null>(null)
  const [hasChecked, setHasChecked] = useState(false)

  // GitHub config
  const [ghToken, setGhToken] = useState('')
  const [ghRepo, setGhRepo] = useState('')
  const [showGhToken, setShowGhToken] = useState(false)
  const [savingConfig, setSavingConfig] = useState(false)
  const [configSaved, setConfigSaved] = useState(false)

  const checkForUpdates = async () => {
    setChecking(true)
    setCheckError('')
    setPrResult(null)

    try {
      const res = await cmsApi<UpdateInfo>('/updates/check')
      if (res.error) {
        setCheckError(res.error)
      } else if (res.data) {
        setUpdateInfo(res.data)
        if (res.data.githubRepo) setGhRepo(res.data.githubRepo)
      }
    } catch {
      setCheckError('Unable to check for updates. Please try again.')
    } finally {
      setChecking(false)
      setHasChecked(true)
    }
  }

  const saveGitHubConfig = async () => {
    setSavingConfig(true)
    setConfigSaved(false)
    try {
      const res = await cmsApi('/updates/config', {
        method: 'PUT',
        body: JSON.stringify({
          ...(ghToken ? { githubToken: ghToken } : {}),
          ...(ghRepo ? { githubRepo: ghRepo } : {}),
        }),
      })
      if (res.error) {
        toast.error(res.error)
      } else {
        toast.success('GitHub configuration saved and encrypted.')
        setConfigSaved(true)
        setGhToken('')
        if (updateInfo) {
          setUpdateInfo({ ...updateInfo, hasGithubToken: true, githubRepo: ghRepo })
        }
      }
    } catch {
      toast.error('Failed to save configuration.')
    } finally {
      setSavingConfig(false)
    }
  }

  const applyUpdate = async () => {
    if (!updateInfo?.latest) return
    setApplying(true)

    try {
      const res = await cmsApi<{ prUrl: string; prNumber: number }>('/updates/apply', {
        method: 'POST',
        body: JSON.stringify({ targetVersion: updateInfo.latest }),
      })

      if (res.error) {
        toast.error(res.error)
      } else if (res.data) {
        setPrResult(res.data)
        toast.success('Update PR created successfully!')
      }
    } catch {
      toast.error('Failed to create update PR. Check your GitHub configuration.')
    } finally {
      setApplying(false)
    }
  }

  useEffect(() => {
    checkForUpdates()
  }, [])

  // Semantic severity tokens so update banners match the rest of the admin in
  // both light and dark mode (no raw palette colors). Concrete keys (not a
  // string-index Record) keep the lookup non-nullable.
  const severityColors = {
    patch: { banner: 'border-brand/30 bg-brand/10', text: 'text-brand', label: 'Patch' },
    minor: { banner: 'border-warning/30 bg-warning/10', text: 'text-warning', label: 'Minor' },
    major: {
      banner: 'border-destructive/30 bg-destructive/10',
      text: 'text-destructive',
      label: 'Major',
    },
  }
  const sev = severityColors[updateInfo?.severity ?? 'patch']
  const ghInputClass =
    'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none'

  return (
    <>
      {/* Current Version Card */}
      <SettingsCard
        title="Actuate CMS"
        description="Keep your CMS up to date with the latest features and security patches."
        actions={
          <button
            type="button"
            onClick={checkForUpdates}
            disabled={checking}
            className="border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-4 py-2 text-sm font-medium transition-colors disabled:opacity-50"
          >
            <RefreshCw size={16} className={checking ? 'animate-spin' : ''} aria-hidden="true" />
            {checking ? 'Checking…' : 'Check for Updates'}
          </button>
        }
      >
        <p className="text-muted-foreground text-sm">
          Current version:{' '}
          <span className="text-foreground font-mono font-medium">
            {updateInfo?.current ?? '…'}
          </span>
        </p>
      </SettingsCard>

      {/* Error State */}
      {checkError && (
        <div
          role="alert"
          className="border-destructive/30 bg-destructive/10 text-destructive flex items-center gap-3 rounded-lg border p-3 text-sm"
        >
          <AlertTriangle size={20} className="shrink-0" aria-hidden="true" />
          <span className="flex-1">{checkError}</span>
          <button
            onClick={checkForUpdates}
            className="border-destructive/40 rounded-md border px-3 py-1 transition-colors hover:opacity-80"
          >
            Retry
          </button>
        </div>
      )}

      {/* Up to Date */}
      {hasChecked && updateInfo && !updateInfo.updateAvailable && !checkError && (
        <div className="border-success/30 bg-success/10 text-success flex items-center gap-3 rounded-lg border p-4">
          <CheckCircle2 size={24} className="shrink-0" aria-hidden="true" />
          <div>
            <h3 className="text-foreground font-medium">You&apos;re up to date!</h3>
            <p className="text-muted-foreground mt-0.5 text-sm">
              Actuate CMS <span className="font-mono">{updateInfo.current}</span> is the latest
              version.
            </p>
          </div>
        </div>
      )}

      {/* Update Available */}
      {updateInfo?.updateAvailable && (
        <>
          <div className={`rounded-lg border p-4 ${sev.banner}`}>
            <div className="flex items-start gap-3">
              <ArrowUpCircle
                size={24}
                className={`mt-0.5 shrink-0 ${sev.text}`}
                aria-hidden="true"
              />
              <div className="flex-1">
                <div className="flex items-center gap-2">
                  <h3 className={`font-medium ${sev.text}`}>Update Available</h3>
                  <span
                    className={`inline-flex items-center rounded border px-2 py-0.5 text-xs font-medium ${sev.banner} ${sev.text}`}
                  >
                    {sev.label}
                  </span>
                </div>
                <p className="text-muted-foreground mt-1 text-sm">
                  <span className="font-mono">{updateInfo.current}</span> &rarr;{' '}
                  <span className="text-foreground font-mono font-medium">{updateInfo.latest}</span>
                  {updateInfo.releaseDate && (
                    <span className="ml-2 text-xs opacity-70">
                      Released {updateInfo.releaseDate}
                    </span>
                  )}
                </p>
              </div>
            </div>

            <div className="mt-4 flex items-center gap-3">
              <button
                type="button"
                onClick={applyUpdate}
                disabled={applying}
                className="bg-brand text-brand-foreground inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:opacity-50"
              >
                {applying ? (
                  <>
                    <Loader2 size={16} className="animate-spin" aria-hidden="true" />
                    Creating PR…
                  </>
                ) : (
                  <>
                    <GitPullRequest size={16} aria-hidden="true" />
                    Create Update PR
                  </>
                )}
              </button>
              <span className="text-muted-foreground text-xs">
                Opens a pull request on your repository
              </span>
            </div>

            {updateInfo.updateCommand && (
              <div className="border-border bg-card mt-3 rounded-md border p-3">
                <p className="text-muted-foreground mb-1 text-xs">Or update manually:</p>
                <code className="bg-muted text-foreground block rounded px-2 py-1.5 font-mono text-xs select-all">
                  {updateInfo.updateCommand}
                </code>
              </div>
            )}
          </div>

          {/* Changelog */}
          {updateInfo.changelog && updateInfo.changelog.length > 0 && (
            <SettingsCard title="Changelog">
              <div className="max-h-64 space-y-2 overflow-y-auto">
                {updateInfo.changelog.map((entry) => (
                  <div key={entry.version} className="flex items-baseline gap-3 text-sm">
                    <span className="text-muted-foreground w-14 shrink-0 font-mono text-xs">
                      {entry.version}
                    </span>
                    <span className="text-muted-foreground w-20 shrink-0 text-xs">
                      {entry.date}
                    </span>
                    <span className="text-foreground">{entry.summary}</span>
                  </div>
                ))}
              </div>
            </SettingsCard>
          )}
        </>
      )}

      {/* PR Created */}
      {prResult && (
        <div className="border-success/30 bg-success/10 rounded-lg border p-4">
          <div className="flex items-start gap-3">
            <GitPullRequest size={20} className="text-success mt-0.5 shrink-0" aria-hidden="true" />
            <div>
              <h3 className="text-foreground font-medium">Pull Request Created</h3>
              <p className="text-muted-foreground mt-1 text-sm">
                PR #{prResult.prNumber} has been created on your repository. Review and merge it to
                apply the update, then run{' '}
                <code className="bg-muted rounded px-1 font-mono text-xs">
                  npx prisma migrate deploy
                </code>
                .
              </p>
              <a
                href={prResult.prUrl}
                target="_blank"
                rel="noopener noreferrer"
                className="text-brand mt-2 inline-flex items-center gap-1.5 text-sm font-medium hover:underline"
              >
                <ExternalLink size={16} aria-hidden="true" />
                View Pull Request
              </a>
            </div>
          </div>
        </div>
      )}

      {/* GitHub Configuration */}
      <SettingsCard
        title="GitHub Integration"
        description="Connect your repository to enable one-click update PRs. Credentials are encrypted at rest (AES-256-GCM)."
      >
        <div className="space-y-4">
          <div>
            <label
              htmlFor="updates-gh-repo"
              className="text-foreground mb-1 block text-sm font-medium"
            >
              Repository
            </label>
            <input
              id="updates-gh-repo"
              type="text"
              value={ghRepo}
              onChange={(e) => setGhRepo(e.target.value)}
              placeholder="owner/repo"
              className={ghInputClass}
            />
            <p className="text-muted-foreground mt-1 text-sm">
              e.g.{' '}
              <code className="bg-muted rounded px-1 font-mono">actuate-media/my-client-site</code>
            </p>
          </div>
          <div>
            <label
              htmlFor="updates-gh-token"
              className="text-foreground mb-1 block text-sm font-medium"
            >
              GitHub Token
              {updateInfo?.hasGithubToken && !ghToken && (
                <span className="text-success ml-2 text-xs font-normal">Saved</span>
              )}
            </label>
            <div className="relative">
              <input
                id="updates-gh-token"
                type={showGhToken ? 'text' : 'password'}
                value={ghToken}
                onChange={(e) => setGhToken(e.target.value)}
                placeholder={
                  updateInfo?.hasGithubToken ? '••••••••••••••••' : 'ghp_... or github_pat_...'
                }
                className={`${ghInputClass} pr-10`}
              />
              <button
                type="button"
                onClick={() => setShowGhToken(!showGhToken)}
                aria-label={showGhToken ? 'Hide token' : 'Show token'}
                className="text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 p-1"
              >
                {showGhToken ? (
                  <EyeOff size={16} aria-hidden="true" />
                ) : (
                  <Eye size={16} aria-hidden="true" />
                )}
              </button>
            </div>
            <p className="text-muted-foreground mt-1 text-sm">
              Needs <code className="bg-muted rounded px-1 font-mono">repo</code> scope. Create at{' '}
              <a
                href="https://github.com/settings/tokens"
                target="_blank"
                rel="noopener noreferrer"
                className="text-brand hover:underline"
              >
                github.com/settings/tokens
              </a>
            </p>
          </div>

          <button
            type="button"
            onClick={saveGitHubConfig}
            disabled={savingConfig || (!ghToken && !ghRepo)}
            className="bg-brand text-brand-foreground inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-opacity hover:opacity-90 disabled:opacity-50"
          >
            {savingConfig ? (
              <>
                <Loader2 size={16} className="animate-spin" aria-hidden="true" />
                Encrypting &amp; Saving…
              </>
            ) : (
              'Save Configuration'
            )}
          </button>
        </div>
      </SettingsCard>

      {/* Help Text */}
      <SettingsCard title="How Updates Work">
        <ul className="text-muted-foreground space-y-1.5 text-sm">
          <li className="flex items-start gap-2">
            <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
              1
            </span>
            <span>
              Click &quot;Check for Updates&quot; to see if a new version is available on npm.
            </span>
          </li>
          <li className="flex items-start gap-2">
            <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
              2
            </span>
            <span>
              Add your GitHub token and repository above. They&apos;re encrypted at rest — never
              stored in plaintext.
            </span>
          </li>
          <li className="flex items-start gap-2">
            <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
              3
            </span>
            <span>
              Click &quot;Create Update PR&quot; to open a pull request that bumps your CMS packages
              automatically.
            </span>
          </li>
          <li className="flex items-start gap-2">
            <span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
              4
            </span>
            <span>
              Review and merge the PR, then deploy. Database migrations run automatically via{' '}
              <code className="bg-muted rounded px-1 font-mono">prisma migrate deploy</code>.
            </span>
          </li>
        </ul>
      </SettingsCard>
    </>
  )
}
