'use client'

import {
  AlertTriangle,
  ChevronDown,
  ChevronRight,
  ImageIcon,
  Library,
  Loader2,
  Trash2,
  Upload,
} from 'lucide-react'
import { useRef, useState } from 'react'

import { MediaPickerModal } from '../../components/MediaPickerModal.js'
import { SettingsCard, SettingsControlRow, SettingsSubsection } from './components.js'
import {
  FAVICON_MIME,
  LOGO_MIME,
  type BrandAssetField,
  type SelectedBrandAsset,
  type UseAppearanceSettings,
} from './useAppearanceSettings.js'

// Derive the file-input accept strings from the validation allow-lists so the
// picker and the validator can never drift apart.
const LOGO_ACCEPT = LOGO_MIME.join(',')
const FAVICON_ACCEPT = FAVICON_MIME.join(',')

function previewSurface(dark: boolean): string {
  return dark ? 'bg-foreground border-border' : 'bg-muted border-border'
}

function LogoField({
  label,
  helper,
  field,
  accept,
  square,
  darkSurface,
  brand,
  assets,
  uploadingField,
  canEdit,
  warning,
  onUpload,
  onSelectFromLibrary,
  onRemove,
}: {
  label: string
  helper: string
  field: BrandAssetField
  accept: string
  square?: boolean
  darkSurface?: boolean
  brand: UseAppearanceSettings['brand']
  assets: UseAppearanceSettings['assets']
  uploadingField: BrandAssetField | null
  canEdit: boolean
  warning?: string
  onUpload: (field: BrandAssetField, file: File) => void
  onSelectFromLibrary: (field: BrandAssetField, item: SelectedBrandAsset) => void
  onRemove: (field: BrandAssetField) => void
}) {
  const inputRef = useRef<HTMLInputElement>(null)
  const [pickerOpen, setPickerOpen] = useState(false)
  // Remember a preview URL that failed to load so a broken/expired asset shows
  // the neutral placeholder icon instead of the browser's broken-image glyph.
  const [thumbErrorUrl, setThumbErrorUrl] = useState<string | null>(null)
  const assetId = brand[field]
  const asset = assetId ? assets[assetId] : undefined
  const uploading = uploadingField === field
  const inputId = `brand-${field}`
  const showPreview = Boolean(asset?.url) && asset?.url !== thumbErrorUrl

  const thumbnail = (
    <div
      className={`flex shrink-0 items-center justify-center overflow-hidden rounded-md border p-2 ${previewSurface(
        Boolean(darkSurface),
      )} ${square ? 'h-12 w-12' : 'h-12 w-20'}`}
      aria-hidden={!asset}
    >
      {showPreview ? (
        // Never stretch/crop — contain preserves aspect ratio + transparency.
        <img
          src={asset!.url}
          alt={`${label} preview`}
          className="max-h-full max-w-full object-contain"
          onError={() => setThumbErrorUrl(asset!.url)}
        />
      ) : (
        <ImageIcon size={18} className="text-muted-foreground" aria-hidden="true" />
      )}
    </div>
  )

  const controls = (
    <>
      <input
        ref={inputRef}
        id={inputId}
        type="file"
        accept={accept}
        aria-label={label}
        className="sr-only"
        disabled={!canEdit || uploading}
        onChange={(e) => {
          const file = e.target.files?.[0]
          if (file) onUpload(field, file)
          if (inputRef.current) inputRef.current.value = ''
        }}
      />
      {asset && (
        <button
          type="button"
          onClick={() => onRemove(field)}
          disabled={!canEdit}
          className="text-muted-foreground hover:text-destructive inline-flex items-center gap-1.5 rounded-md px-2 py-1.5 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50"
          aria-label={`Remove ${label.toLowerCase()}`}
        >
          <Trash2 size={14} aria-hidden="true" /> Remove
        </button>
      )}
      <button
        type="button"
        onClick={() => setPickerOpen(true)}
        disabled={!canEdit || uploading}
        aria-label={`Choose ${label.toLowerCase()} from media library`}
        className="border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50"
      >
        <Library size={14} aria-hidden="true" /> Media library
      </button>
      <button
        type="button"
        onClick={() => inputRef.current?.click()}
        disabled={!canEdit || uploading}
        aria-label={`${asset ? 'Replace' : 'Upload'} ${label.toLowerCase()}`}
        className="border-border text-foreground hover:bg-accent inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50"
      >
        {uploading ? (
          <Loader2 size={14} className="animate-spin" aria-hidden="true" />
        ) : (
          <Upload size={14} aria-hidden="true" />
        )}
        {asset ? 'Replace' : 'Upload'}
      </button>
      <MediaPickerModal
        open={pickerOpen}
        onClose={() => setPickerOpen(false)}
        accept={accept}
        libraryOnly
        onSelect={() => {}}
        onSelectItem={(item) => {
          onSelectFromLibrary(field, {
            id: item.id,
            url: item.url,
            mimeType: item.mimeType,
            width: item.width,
            height: item.height,
          })
        }}
      />
    </>
  )

  return (
    <div>
      <SettingsControlRow
        leading={thumbnail}
        label={label}
        description={helper}
        control={controls}
      />
      {warning && (
        <p
          className="text-warning mt-2 flex items-start gap-1.5 text-sm"
          role="status"
          aria-live="polite"
        >
          <AlertTriangle size={14} className="mt-0.5 shrink-0" aria-hidden="true" /> {warning}
        </p>
      )}
    </div>
  )
}

function AdminBrandSourceToggle({
  mode,
  canEdit,
  onChange,
}: {
  mode: UseAppearanceSettings['brand']['mode']
  canEdit: boolean
  onChange: (mode: 'inheritPublicBrand' | 'customAdminBrand') => void
}) {
  return (
    <div
      role="radiogroup"
      aria-label="Brand source"
      className="border-border bg-muted inline-flex rounded-md border p-0.5"
    >
      {(
        [
          ['inheritPublicBrand', 'Inherit public brand'],
          ['customAdminBrand', 'Custom admin logo'],
        ] as const
      ).map(([value, text]) => {
        const active = mode === value
        return (
          <button
            key={value}
            type="button"
            role="radio"
            aria-checked={active}
            disabled={!canEdit}
            onClick={() => onChange(value)}
            className={`rounded px-3 py-1.5 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${
              active
                ? 'bg-card text-foreground shadow-sm'
                : 'text-muted-foreground hover:text-foreground'
            }`}
          >
            {text}
          </button>
        )
      })}
    </div>
  )
}

export function BrandingCard({ s, canEdit }: { s: UseAppearanceSettings; canEdit: boolean }) {
  const warningFor = (field: BrandAssetField): string | undefined =>
    s.issues.find((i) => i.field === field && i.severity === 'warning')?.message

  const custom = s.brand.mode === 'customAdminBrand'

  const logoFieldProps = {
    accept: LOGO_ACCEPT,
    brand: s.brand,
    assets: s.assets,
    uploadingField: s.uploadingField,
    canEdit,
    onUpload: s.uploadAsset,
    onSelectFromLibrary: s.selectAsset,
    onRemove: s.removeAsset,
  }

  return (
    <SettingsCard
      title="Branding"
      description="Logos shown in the admin sidebar and on the public site."
    >
      <div className="space-y-5">
        <LogoField
          label="Primary logo"
          helper="SVG, PNG, WebP, JPEG, GIF, or AVIF, up to 1MB. Best for the public header and full admin sidebar."
          field="publicPrimaryLogoAssetId"
          warning={warningFor('publicPrimaryLogoAssetId')}
          {...logoFieldProps}
        />

        <LogoField
          label="Favicon / app icon source"
          helper="32×32 SVG, PNG, or WebP. A larger square image is fine — it scales down cleanly."
          field="faviconSourceAssetId"
          square
          warning={warningFor('faviconSourceAssetId')}
          {...logoFieldProps}
          accept={FAVICON_ACCEPT}
        />

        {/* Advanced logo variants disclosure (Logo mark + Dark mode logo). */}
        <div className="border-border border-t pt-4">
          <button
            type="button"
            onClick={() => s.setShowAdvanced(!s.showAdvanced)}
            aria-expanded={s.showAdvanced}
            className="text-foreground hover:text-brand inline-flex items-center gap-1.5 text-sm font-medium transition-colors"
          >
            {s.showAdvanced ? (
              <ChevronDown size={16} aria-hidden="true" />
            ) : (
              <ChevronRight size={16} aria-hidden="true" />
            )}
            Advanced logo variants
          </button>

          {s.showAdvanced && (
            <div className="mt-4 space-y-5">
              <LogoField
                label="Logo mark"
                helper="Square icon or mark. Used for the collapsed sidebar, compact UI, and app icons."
                field="publicLogoMarkAssetId"
                square
                warning={warningFor('publicLogoMarkAssetId')}
                {...logoFieldProps}
              />
              <LogoField
                label="Dark mode logo"
                helper="Optional. Used on dark backgrounds or the dark admin theme."
                field="publicDarkLogoAssetId"
                darkSurface
                warning={warningFor('publicDarkLogoAssetId')}
                {...logoFieldProps}
              />
            </div>
          )}
        </div>

        {/* Admin branding — admin inherits the public brand by default. */}
        <SettingsSubsection
          title="Admin branding"
          description="By default the admin reuses your public brand. Override it for a distinct internal look."
        >
          <div className="mt-4 space-y-5">
            <SettingsControlRow
              label="Brand source"
              description="Choose whether the admin inherits the public brand or uses a custom logo."
              control={
                <AdminBrandSourceToggle
                  mode={s.brand.mode}
                  canEdit={canEdit}
                  onChange={s.setBrandingMode}
                />
              }
            />

            {custom && (
              <div className="space-y-5">
                <LogoField
                  label="Admin primary logo"
                  helper="Shown in the admin sidebar instead of the public logo."
                  field="adminPrimaryLogoAssetId"
                  warning={warningFor('adminPrimaryLogoAssetId')}
                  {...logoFieldProps}
                />
                <LogoField
                  label="Admin logo mark"
                  helper="Square mark for the collapsed admin sidebar."
                  field="adminLogoMarkAssetId"
                  square
                  warning={warningFor('adminLogoMarkAssetId')}
                  {...logoFieldProps}
                />
              </div>
            )}
          </div>
        </SettingsSubsection>

        {/* Default alt text */}
        <div className="border-border border-t pt-4">
          <label htmlFor="brand-alt" className="text-foreground block text-base font-medium">
            Logo alt text
          </label>
          <p className="text-muted-foreground mt-0.5 mb-2 text-sm">
            Used by screen readers on the public site. Defaults to the Site Title when empty.
          </p>
          <input
            id="brand-alt"
            type="text"
            value={s.brand.defaultLogoAltText ?? ''}
            disabled={!canEdit}
            onChange={(e) => s.setAltText(e.target.value)}
            placeholder="Site Title"
            className="border-border bg-input-background text-foreground focus-visible:ring-ring w-full max-w-md rounded-md border px-3 py-2 text-base focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50"
          />
        </div>
      </div>

      {s.saveError && (
        <p className="text-destructive mt-4 text-sm" role="alert">
          {s.saveError}
        </p>
      )}
    </SettingsCard>
  )
}
