import { useRef, useState } from 'react'
import { api } from '../../../api/client.js'
import { useSite } from '../../../contexts/SiteContext.jsx'

// Admin · Appearance → Brand assets (docs/website/THEMING_AND_NAV.md §6.3).
//
// Three slots, each an override layer over the matching BRAND_* env value. An
// empty slot is not "no image" — it is "whatever this instance was deployed
// with", which is why every row shows what it currently resolves to rather than
// an empty box.
//
// Unlike the theme form above, an upload SAVES IMMEDIATELY: the file and the
// settings row are written by one request, because an upload that stored a file
// and then waited for a Save press would leave litter in /uploads whenever the
// admin changed their mind. Clearing a slot is the same deal in reverse.
const SLOTS = [
  {
    id: 'logo',
    label: 'Logo',
    accept: 'image/png,image/jpeg,image/webp,image/avif,image/gif',
    limit: '1 MB',
    envVar: 'BRAND_LOGO',
    help: 'Shown beside the moon in the site header, the admin sidebar and the player portal, and used as the link preview image when a page is shared.',
  },
  {
    id: 'hero',
    label: 'Hero image',
    accept: 'image/png,image/jpeg,image/webp,image/avif,image/gif',
    limit: '8 MB',
    envVar: 'BRAND_HERO',
    // §4.9: the hero editor's own background beats this, and an admin who does
    // not know that files a bug against a working system.
    help: 'The image behind the portal hero. If the hero editor has its own background image set, that wins over this one.',
  },
  {
    id: 'favicon',
    label: 'Favicon',
    accept: 'image/png',
    limit: '512 KB',
    envVar: 'BRAND_FAVICON',
    // §4.10: .ico would mean adding a type to the upload allowlist, and the
    // stored extension coming from that allowlist is what makes uploads safe.
    help: 'The browser tab icon. PNG only — a 32×32 or 64×64 square works everywhere.',
  },
]

export default function BrandAssetsPanel({ initial }) {
  const { brand, refresh: refreshSite } = useSite()
  const [assets, setAssets] = useState(initial || {})
  const [busySlot, setBusySlot] = useState('')
  const [error, setError] = useState('')
  const inputs = useRef({})

  async function upload(slot, file) {
    if (!file) return
    setBusySlot(slot)
    setError('')
    try {
      const res = await api.admin.uploadBrandAsset(slot, file)
      setAssets(res.brand_assets || {})
      await refreshSite()
    } catch (err) {
      setError(err.message || 'Could not upload that image.')
    } finally {
      setBusySlot('')
      // Let the same file be picked again after a failure — a file input holds
      // its value, so re-choosing it would fire no change event.
      if (inputs.current[slot]) inputs.current[slot].value = ''
    }
  }

  async function clear(slot) {
    setBusySlot(slot)
    setError('')
    try {
      const next = { ...assets }
      delete next[slot]
      // Clearing the last override deletes the row rather than storing `{}` —
      // absence of the row is what selects the env defaults (§2), and a stored
      // empty object would be a different state that means the same thing.
      if (Object.keys(next).length) await api.admin.updateSettings({ brand_assets: next })
      else await api.admin.resetSetting('brand_assets')
      setAssets(next)
      await refreshSite()
    } catch (err) {
      setError(err.message || 'Could not clear that asset.')
    } finally {
      setBusySlot('')
    }
  }

  return (
    <div>
      <span className="field-label">Brand assets</span>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14, marginTop: 8 }}>
        {SLOTS.map((slot) => {
          const overridden = Boolean(assets[slot.id])
          // What the site actually uses right now: the override, or the env
          // value the brand block already resolved for us.
          const effective = assets[slot.id] || brand[slot.id] || ''
          return (
            <div
              key={slot.id}
              style={{
                display: 'flex',
                alignItems: 'flex-start',
                gap: 14,
                padding: 12,
                border: '1px solid var(--line)',
                borderRadius: 'var(--radius-input)',
              }}
            >
              <div
                style={{
                  width: 76,
                  height: 48,
                  flex: '0 0 auto',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  border: '1px solid var(--line-soft)',
                  borderRadius: 6,
                  background: 'var(--bg-deep)',
                  overflow: 'hidden',
                }}
              >
                {effective ? (
                  <img src={effective} alt="" style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
                ) : (
                  <span className="sans dim" style={{ fontSize: '0.68rem' }}>
                    none
                  </span>
                )}
              </div>

              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="sans" style={{ fontSize: '0.86rem', color: 'var(--ink)' }}>
                  {slot.label}
                </div>
                <div className="sans dim" style={{ fontSize: '0.74rem', lineHeight: 1.6, marginTop: 2 }}>
                  {slot.help}
                </div>
                <div className="sans dim" style={{ fontSize: '0.72rem', marginTop: 6 }}>
                  {overridden ? (
                    <>
                      Uploaded override — <code>{assets[slot.id]}</code>
                    </>
                  ) : effective ? (
                    <>
                      Using the deployed default from <code>{slot.envVar}</code>
                    </>
                  ) : (
                    <>
                      Not set — <code>{slot.envVar}</code> is empty, so nothing is rendered
                    </>
                  )}
                </div>

                <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginTop: 8, flexWrap: 'wrap' }}>
                  <input
                    ref={(el) => {
                      inputs.current[slot.id] = el
                    }}
                    type="file"
                    accept={slot.accept}
                    disabled={Boolean(busySlot)}
                    onChange={(e) => upload(slot.id, e.target.files?.[0])}
                    className="sans"
                    style={{ fontSize: '0.74rem', maxWidth: 240 }}
                    aria-label={`Upload a ${slot.label.toLowerCase()}`}
                  />
                  <span className="sans dim" style={{ fontSize: '0.7rem' }}>
                    max {slot.limit}
                  </span>
                  {overridden && (
                    <button
                      type="button"
                      onClick={() => clear(slot.id)}
                      disabled={Boolean(busySlot)}
                      className="sans"
                      title={`Go back to ${slot.envVar}`}
                      style={linkBtn}
                    >
                      {busySlot === slot.id ? 'working…' : 'clear'}
                    </button>
                  )}
                </div>
              </div>
            </div>
          )
        })}
      </div>
      {error && (
        <span className="sans" style={{ display: 'block', marginTop: 8, color: '#d98b84', fontSize: '0.85rem' }}>
          {error}
        </span>
      )}
      <span className="sans dim" style={{ display: 'block', marginTop: 8, fontSize: '0.76rem' }}>
        Uploads apply as soon as they finish — there is nothing to save here. The footer’s “powered by
        Runic Gateway” mark is the project’s badge, not this instance’s, and never changes.
      </span>
    </div>
  )
}

const linkBtn = {
  border: 'none',
  background: 'transparent',
  color: 'var(--accent)',
  fontSize: '0.72rem',
  cursor: 'pointer',
  padding: 0,
}
