'use client'

import {
  AlertTriangle,
  ArrowUpCircle,
  CheckCircle2,
  Database,
  ExternalLink,
  Eye,
  EyeOff,
  GitPullRequest,
  Loader2,
  Lock,
  Puzzle,
  RefreshCw,
  ShieldAlert,
} from 'lucide-react'
import { useState, type ReactNode } from 'react'

import { SettingsCard, SettingsControlRow, SettingsSaveBar } from './components.js'
import {
  useUpdates,
  type UpdateChangeType,
  type UpdateChangelogItem,
  type UpdateInfo,
} from './useUpdates.js'

const SEVERITY: Record<
  NonNullable<UpdateInfo['severity']>,
  { banner: string; text: string; label: string }
> = {
  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',
  },
  security: {
    banner: 'border-destructive/40 bg-destructive/15',
    text: 'text-destructive',
    label: 'Security',
  },
}

const CHANGE_TYPE: Record<UpdateChangeType, { label: string; className: string }> = {
  feature: { label: 'Feature', className: 'border-brand/30 bg-brand/10 text-brand' },
  improvement: {
    label: 'Improvement',
    className: 'border-border bg-muted text-muted-foreground',
  },
  fix: { label: 'Fix', className: 'border-border bg-muted text-muted-foreground' },
  breaking: {
    label: 'Breaking',
    className: 'border-destructive/30 bg-destructive/10 text-destructive',
  },
  security: {
    label: 'Security',
    className: 'border-destructive/40 bg-destructive/15 text-destructive',
  },
  deprecation: { label: 'Deprecated', className: 'border-warning/30 bg-warning/10 text-warning' },
}

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'

/** Group a flat changelog list into per-version buckets (order preserved). */
function groupByVersion(
  changelog: UpdateChangelogItem[],
): Array<{ version: string; date: string; items: UpdateChangelogItem[] }> {
  const groups: Array<{ version: string; date: string; items: UpdateChangelogItem[] }> = []
  for (const item of changelog) {
    const last = groups[groups.length - 1]
    if (last && last.version === item.version) {
      last.items.push(item)
    } else {
      groups.push({ version: item.version, date: item.date, items: [item] })
    }
  }
  return groups
}

function ChangeTypeBadge({ type }: { type?: UpdateChangeType }) {
  if (!type) return null
  const meta = CHANGE_TYPE[type]
  return (
    <span
      className={`inline-flex shrink-0 items-center rounded border px-1.5 py-0.5 text-xs font-medium ${meta.className}`}
    >
      {meta.label}
    </span>
  )
}

/** A bordered notice row used for migration / breaking-change callouts. */
function Notice({
  tone,
  icon,
  title,
  children,
}: {
  tone: 'warning' | 'destructive'
  icon: ReactNode
  title: string
  children?: ReactNode
}) {
  const toneClass =
    tone === 'destructive'
      ? 'border-destructive/30 bg-destructive/10 text-destructive'
      : 'border-warning/30 bg-warning/10 text-warning'
  return (
    <div className={`mt-3 flex items-start gap-2.5 rounded-md border p-3 ${toneClass}`}>
      <span className="mt-0.5 shrink-0" aria-hidden="true">
        {icon}
      </span>
      <div className="min-w-0 text-sm">
        <p className="font-medium">{title}</p>
        {children && <div className="text-foreground/80 mt-1 space-y-1">{children}</div>}
      </div>
    </div>
  )
}

export interface UpdatesTabProps {
  /** Current admin role — gates the write actions (config + Create PR). */
  role?: string
}

export function UpdatesTab({ role }: UpdatesTabProps) {
  const {
    info,
    checking,
    hasChecked,
    error,
    applying,
    prResult,
    canManage,
    form,
    setField,
    dirty,
    repoError,
    hasErrors,
    saveState,
    save,
    reset,
    check,
    apply,
  } = useUpdates({ role })

  const [showToken, setShowToken] = useState(false)

  const severity = info?.updateAvailable ? SEVERITY[info.severity ?? 'patch'] : null
  const changelogGroups = info?.changelog ? groupByVersion(info.changelog) : []

  return (
    <>
      {/* Current version */}
      <SettingsCard
        title="Actuate CMS"
        description="Keep your CMS up to date with the latest features and security patches."
        actions={
          <button
            type="button"
            onClick={check}
            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">{info?.current ?? '…'}</span>
        </p>
      </SettingsCard>

      {/* Error */}
      {error && (
        <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">{error}</span>
          <button
            type="button"
            onClick={check}
            className="border-destructive/40 rounded-md border px-3 py-1 transition-colors hover:opacity-80"
          >
            Retry
          </button>
        </div>
      )}

      {/* Up to date */}
      {hasChecked && info && !info.updateAvailable && !error && (
        <div className="border-success/30 bg-success/10 flex items-center gap-3 rounded-lg border p-4">
          <CheckCircle2 size={24} className="text-success 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">{info.current}</span> is the latest version.
            </p>
          </div>
        </div>
      )}

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

          {info.hasMigrations && (
            <Notice
              tone="warning"
              icon={<Database size={16} />}
              title="Database migrations required"
            >
              <p>
                Run{' '}
                <code className="bg-muted rounded px-1 font-mono text-xs">
                  npx prisma migrate deploy
                </code>{' '}
                after upgrading. On Vercel this runs automatically at build time.
              </p>
            </Notice>
          )}

          {info.breakingChanges && info.breakingChanges.length > 0 && (
            <Notice
              tone="destructive"
              icon={<AlertTriangle size={16} />}
              title="Breaking changes in this release"
            >
              <ul className="list-disc space-y-1 pl-4">
                {info.breakingChanges.map((c, i) => (
                  <li key={i}>{c}</li>
                ))}
              </ul>
            </Notice>
          )}

          <div className="mt-4 flex flex-wrap items-center gap-3">
            {canManage ? (
              <button
                type="button"
                onClick={apply}
                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 inline-flex items-center gap-1.5 text-xs">
                <Lock size={14} aria-hidden="true" />
                Ask an administrator to apply this update.
              </span>
            )}
            {canManage && (
              <span className="text-muted-foreground text-xs">
                Opens a pull request on your repository
              </span>
            )}
          </div>

          {info.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">
                {info.updateCommand}
              </code>
            </div>
          )}
        </div>
      )}

      {/* Changelog */}
      {info?.updateAvailable && changelogGroups.length > 0 && (
        <SettingsCard
          title="Changelog"
          description={
            info.source === 'npm'
              ? 'Version history from npm. Connect the update server for full release notes.'
              : "What's new since your current version."
          }
        >
          <div className="max-h-80 space-y-4 overflow-y-auto pr-1">
            {changelogGroups.map((group) => (
              <div
                key={group.version}
                className="border-border border-b pb-3 last:border-0 last:pb-0"
              >
                <div className="mb-1.5 flex items-baseline gap-3">
                  <span className="text-foreground font-mono text-sm font-medium">
                    {group.version}
                  </span>
                  {group.date && (
                    <span className="text-muted-foreground text-xs">{group.date}</span>
                  )}
                </div>
                <ul className="space-y-1.5">
                  {group.items.map((item, i) => (
                    <li key={i} className="flex items-start gap-2 text-sm">
                      <ChangeTypeBadge type={item.type} />
                      <span className="text-muted-foreground min-w-0">{item.summary}</span>
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        </SettingsCard>
      )}

      {/* Plugin compatibility */}
      {info?.updateAvailable && info.pluginCompatibility && info.pluginCompatibility.length > 0 && (
        <SettingsCard
          title="Plugin compatibility"
          description="Latest published versions of the official plugins for this release."
        >
          <ul className="grid gap-2 sm:grid-cols-2">
            {info.pluginCompatibility.map((plugin) => (
              <li
                key={plugin.name}
                className="border-border flex items-center justify-between gap-3 rounded-md border px-3 py-2 text-sm"
              >
                <span className="text-foreground inline-flex min-w-0 items-center gap-2">
                  <Puzzle size={14} className="text-muted-foreground shrink-0" aria-hidden="true" />
                  <span className="truncate font-mono text-xs">
                    {plugin.name.replace('@actuate-media/', '')}
                  </span>
                </span>
                <span className="text-muted-foreground inline-flex shrink-0 items-center gap-1.5">
                  {plugin.minVersion && (
                    <span className="font-mono text-xs">{plugin.minVersion}</span>
                  )}
                  <CheckCircle2 size={14} className="text-success" aria-hidden="true" />
                </span>
              </li>
            ))}
          </ul>
        </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 integration — admins only */}
      {canManage && (
        <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">
            <SettingsControlRow
              label="Repository"
              htmlFor="updates-gh-repo"
              align="start"
              description={
                <>
                  e.g.{' '}
                  <code className="bg-muted rounded px-1 font-mono">
                    actuate-media/my-client-site
                  </code>
                </>
              }
              control={
                <div className="w-72 max-w-full">
                  <input
                    id="updates-gh-repo"
                    type="text"
                    value={form.githubRepo}
                    onChange={(e) => setField('githubRepo', e.target.value)}
                    placeholder="owner/repo"
                    aria-invalid={Boolean(repoError)}
                    aria-describedby={repoError ? 'updates-gh-repo-error' : undefined}
                    className={ghInputClass}
                  />
                  {repoError && (
                    <p id="updates-gh-repo-error" className="text-destructive mt-1 text-xs">
                      {repoError}
                    </p>
                  )}
                </div>
              }
            />

            <SettingsControlRow
              label={
                <span className="inline-flex items-center gap-2">
                  GitHub token
                  {info?.hasGithubToken && !form.githubToken && (
                    <span className="text-success text-xs font-normal">Saved</span>
                  )}
                </span>
              }
              htmlFor="updates-gh-token"
              align="start"
              description={
                <>
                  Needs <code className="bg-muted rounded px-1 font-mono">repo</code> scope. Create
                  one at{' '}
                  <a
                    href="https://github.com/settings/tokens"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-brand hover:underline"
                  >
                    github.com/settings/tokens
                  </a>
                  .
                </>
              }
              control={
                <div className="relative w-72 max-w-full">
                  <input
                    id="updates-gh-token"
                    type={showToken ? 'text' : 'password'}
                    value={form.githubToken}
                    onChange={(e) => setField('githubToken', e.target.value)}
                    placeholder={
                      info?.hasGithubToken ? '••••••••••••••••' : 'ghp_… or github_pat_…'
                    }
                    className={`${ghInputClass} pr-10`}
                  />
                  <button
                    type="button"
                    onClick={() => setShowToken((s) => !s)}
                    aria-label={showToken ? 'Hide token' : 'Show token'}
                    className="text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 p-1"
                  >
                    {showToken ? (
                      <EyeOff size={16} aria-hidden="true" />
                    ) : (
                      <Eye size={16} aria-hidden="true" />
                    )}
                  </button>
                </div>
              }
            />
          </div>

          <SettingsSaveBar
            dirty={dirty}
            canEdit={canManage}
            hasErrors={hasErrors}
            saveState={saveState}
            onSave={save}
            onReset={reset}
          />
        </SettingsCard>
      )}

      {/* Help */}
      <SettingsCard title="How Updates Work">
        <ol className="text-muted-foreground space-y-1.5 text-sm">
          {[
            'Click “Check for Updates” to see if a new version is available.',
            'Add your GitHub token and repository above (admins only). They’re encrypted at rest — never stored in plaintext.',
            'Click “Create Update PR” to open a pull request that bumps your CMS packages automatically.',
            'Review and merge the PR, then deploy. Database migrations run automatically via prisma migrate deploy.',
          ].map((step, i) => (
            <li key={i} 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">
                {i + 1}
              </span>
              <span>{step}</span>
            </li>
          ))}
        </ol>
      </SettingsCard>
    </>
  )
}
