import { useMemo, useState } from 'react'
import PublicLayout from '../../components/PublicLayout.jsx'
import PageHeader from '../../components/PageHeader.jsx'
import { Loading, ErrorState } from '../../components/PageState.jsx'
import { useAsync } from '../../lib/useAsync.js'
import { useShardFeed } from '../../lib/useShardFeed.js'
import { crestFor } from '../../data/cityCrests.js'
import { api } from '../../api/client.js'

// The town-governor board (City Loyalty). Loaded from /public/shard/governors,
// kept live by merging city.update deltas by city. Empty on shards without the
// City Loyalty system. Each city card links to its term history (look-back).
const GOV_KINDS = new Set(['city.update'])

const PHASE = {
  none: null,
  nominate: { label: 'Nominations open', color: '#7f8fd0' },
  vote: { label: 'Voting', color: '#e6c26a' },
  pending: { label: 'Result pending', color: '#c9a24b' },
}

// A short "in 3d" / "in 5h" for a future ISO timestamp (autoPickAt).
function until(iso) {
  if (!iso) return ''
  const ms = new Date(iso).getTime() - Date.now()
  if (!Number.isFinite(ms) || ms <= 0) return ''
  const mins = Math.round(ms / 60000)
  if (mins < 60) return `in ${mins}m`
  const hrs = Math.round(mins / 60)
  if (hrs < 24) return `in ${hrs}h`
  return `in ${Math.round(hrs / 24)}d`
}

function fmtDate(ms) {
  if (ms == null) return ''
  return new Date(Number(ms)).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })
}

function CityCrest({ city, size = 44 }) {
  const c = crestFor(city)
  return (
    <span
      aria-hidden="true"
      style={{
        flex: 'none', width: size, height: size, borderRadius: '50%',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        fontSize: size * 0.5, background: 'rgba(255,255,255,0.04)',
        border: `2px solid ${c.color}`, boxShadow: `0 0 10px ${c.color}22`,
      }}
    >
      {c.sigil}
    </span>
  )
}

// Collapsible term history for one city, fetched on demand from the ledger.
function TermHistory({ city }) {
  const [open, setOpen] = useState(false)
  const { loading, error, data } = useAsync(
    () => (open ? api.shard.governorHistory(city, 25) : Promise.resolve(null)),
    [open, city],
  )
  return (
    <div style={{ marginTop: 12 }}>
      <button
        type="button"
        className="sans"
        onClick={() => setOpen((v) => !v)}
        style={{ background: 'none', border: 'none', color: 'var(--accent)', cursor: 'pointer', padding: 0, fontSize: '0.76rem' }}
      >
        {open ? 'Hide past governors' : 'Past governors →'}
      </button>
      {open && (
        <div style={{ marginTop: 8 }}>
          {loading && <p className="sans dim" style={{ margin: 0, fontSize: '0.8rem' }}>Loading…</p>}
          {error && <p className="sans dim" style={{ margin: 0, fontSize: '0.8rem' }}>Could not load history.</p>}
          {data && data.length === 0 && (
            <p className="sans dim" style={{ margin: 0, fontSize: '0.8rem' }}>No recorded terms yet.</p>
          )}
          {data && data.length > 0 && (
            <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 5 }}>
              {data.map((t, i) => (
                <li key={i} className="sans" style={{ display: 'flex', justifyContent: 'space-between', gap: 10, fontSize: '0.8rem', color: 'var(--ink)' }}>
                  <span style={{ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                    {t.governor?.name || 'Vacant'}
                  </span>
                  <span className="dim" style={{ flex: 'none', fontSize: '0.72rem' }}>
                    {fmtDate(t.startedAt)}{t.endedAt ? ` – ${fmtDate(t.endedAt)}` : ' – present'}
                  </span>
                </li>
              ))}
            </ul>
          )}
        </div>
      )}
    </div>
  )
}

function CityCard({ c }) {
  const phase = PHASE[c.electionPhase] || null
  const gov = c.governor
  return (
    <div className="panel" style={{ padding: 18 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        <CityCrest city={c.city} />
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
            <strong className="display" style={{ fontSize: '1.05rem', color: 'var(--head)' }}>
              {crestFor(c.city).label || c.city}
            </strong>
            {phase && (
              <span className="sans" style={{ flex: 'none', fontSize: '0.66rem', letterSpacing: '0.06em', textTransform: 'uppercase', color: phase.color, border: `1px solid ${phase.color}66`, borderRadius: 999, padding: '2px 8px' }}>
                {phase.label}
              </span>
            )}
          </div>
          <div className="sans" style={{ marginTop: 3, fontSize: '0.9rem', color: gov ? 'var(--ink)' : 'var(--muted)' }}>
            {gov ? (
              <>Governor <strong style={{ color: 'var(--head)' }}>{gov.name}</strong></>
            ) : (
              'Seat vacant'
            )}
          </div>
        </div>
      </div>

      {c.electionPhase && c.electionPhase !== 'none' && (
        <div className="sans dim" style={{ marginTop: 10, fontSize: '0.78rem' }}>
          {c.candidates ? `${c.candidates} candidate${c.candidates === 1 ? '' : 's'}` : 'No candidates yet'}
          {c.autoPickAt && until(c.autoPickAt) ? ` · resolves ${until(c.autoPickAt)}` : ''}
        </div>
      )}

      <TermHistory city={c.city} />
    </div>
  )
}

export default function Governors() {
  const { loading, error, data } = useAsync(() => api.shard.governors())
  const { events, connected } = useShardFeed({ filter: GOV_KINDS, max: 30 })

  const board = useMemo(() => {
    const map = new Map()
    for (const c of data || []) if (c && c.city) map.set(c.city, c)
    for (let i = events.length - 1; i >= 0; i -= 1) {
      const ev = events[i]
      if (ev.kind === 'city.update' && ev.city) map.set(ev.city, ev)
    }
    return [...map.values()].sort((a, b) => (a.city || '').localeCompare(b.city || ''))
  }, [data, events])

  return (
    <PublicLayout section="website">
      <div className="shell-narrow page-body">
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16 }}>
          <PageHeader eyebrow="Live" title="Governors of Britannia" lead="Who rules each city, and where the next election stands." />
          <span className="sans" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: '0.74rem', color: connected ? '#7fd0a4' : 'var(--muted)', flex: 'none', marginTop: 6 }}>
            <span style={{ width: 8, height: 8, borderRadius: '50%', background: connected ? '#7fd0a4' : 'var(--dim)' }} />
            {connected ? 'Live' : 'Offline'}
          </span>
        </div>

        {loading && <Loading />}
        {error && <ErrorState message="Could not load the governor board right now." />}

        {!loading && !error && (
          <>
            {board.length === 0 ? (
              <section className="panel" style={{ padding: 24, textAlign: 'center' }}>
                <p className="sans dim" style={{ margin: 0 }}>
                  City Loyalty governance is not enabled on this shard.
                </p>
              </section>
            ) : (
              <div className="grid-2" style={{ gap: 12 }}>
                {board.map((c) => <CityCard key={c.city} c={c} />)}
              </div>
            )}
          </>
        )}
      </div>
    </PublicLayout>
  )
}
