import { useCallback, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { Loading, ErrorState } from './PageState.jsx'
import ShardAccountActions from './ShardAccountActions.jsx'
import CreateGameAccountForm from './CreateGameAccountForm.jsx'
import { api } from '../api/client.js'

// Shared game-account linking + character roster, used by both the player portal
// (/player) and the staff account page (/admin/account). `scope` is the api
// object with { link, accounts, roster } (player or admin self-service); `charTo`
// maps a serial to the route for that character's sheet. `readOnly` drops the
// link forms and self-voice copy for the admin case where staff view *another*
// user's accounts (no `scope.link`) at /admin/users/:id.

function LinkForm({ scope, onLinked, compact }) {
  const [code, setCode] = useState('')
  const [busy, setBusy] = useState(false)
  const [msg, setMsg] = useState('')
  const [error, setError] = useState('')

  async function submit(e) {
    e.preventDefault()
    setMsg(''); setError('')
    if (!code.trim()) return
    setBusy(true)
    try {
      const { account } = await scope.link(code.trim())
      setMsg(`Linked ${account}.`)
      setCode('')
      await onLinked()
    } catch (err) {
      setError(err.message || 'Could not link that code.')
    } finally {
      setBusy(false)
    }
  }

  return (
    <form onSubmit={submit} style={{ display: 'flex', gap: 10, alignItems: 'flex-end', flexWrap: 'wrap', marginTop: compact ? 0 : 6 }}>
      <label style={{ display: 'block' }}>
        {!compact && <span className="field-label">Link code</span>}
        <input
          type="text"
          value={code}
          onChange={(e) => setCode(e.target.value.toUpperCase())}
          className="input"
          autoComplete="off"
          placeholder="AB12CD"
          style={{ maxWidth: 180, textTransform: 'uppercase', letterSpacing: '0.12em' }}
        />
      </label>
      <button type="submit" disabled={busy || !code.trim()} className="btn btn-primary btn-sq">
        {busy ? 'Linking…' : 'Link account'}
      </button>
      {msg && <span className="sans" style={{ color: '#7fd0a4', fontSize: '0.85rem' }}>{msg}</span>}
      {error && <span className="sans" style={{ color: '#d98b84', fontSize: '0.85rem' }}>{error}</span>}
    </form>
  )
}

function AccountRoster({ scope, account, charTo }) {
  const [roster, setRoster] = useState(null)
  const [error, setError] = useState('')
  const [unavailable, setUnavailable] = useState(false)

  const load = useCallback(async () => {
    setError(''); setUnavailable(false)
    try {
      setRoster(await scope.roster(account))
    } catch (err) {
      if (err.status === 503) setUnavailable(true)
      else setError(err.message || 'Could not load this account.')
    }
  }, [scope, account])
  useEffect(() => { load() }, [load])

  if (unavailable) {
    return (
      <div>
        <p className="sans" style={{ margin: '0 0 8px', color: '#e0b070', fontSize: '0.85rem' }}>The game server is restarting — try again shortly.</p>
        <button className="pill" onClick={load}>Retry</button>
      </div>
    )
  }
  if (error) return <p className="sans" style={{ margin: 0, color: '#d98b84', fontSize: '0.85rem' }}>{error}</p>
  if (!roster) return <p className="sans dim" style={{ margin: 0, fontSize: '0.82rem' }}>Loading…</p>

  const chars = roster.chars || []
  if (chars.length === 0) return <p className="sans dim" style={{ margin: 0, fontSize: '0.84rem' }}>No characters on this account.</p>

  return (
    <div className="grid-2" style={{ gap: 12 }}>
      {chars.map((c) => (
        <Link
          key={c.serial}
          to={charTo(c.serial)}
          style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', border: '1px solid var(--line)', borderRadius: 10, textDecoration: 'none', background: 'rgba(255,255,255,0.02)' }}
        >
          <span style={{ flex: 'none', width: 40, height: 40, borderRadius: '50%', background: 'linear-gradient(180deg,#2a3a52,#1a2536)', border: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#d8e2ef', fontSize: '1rem', textTransform: 'uppercase' }}>
            {(c.name || '?').charAt(0)}
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="display" style={{ color: 'var(--head)', fontSize: '1.02rem' }}>{c.name}</div>
            <div className="sans" style={{ fontSize: '0.76rem', color: c.online ? '#7fd0a4' : 'var(--muted)' }}>{c.online ? 'Online' : 'Offline'}</div>
          </div>
          <span className="sans dim" style={{ fontSize: '1.1rem' }}>›</span>
        </Link>
      ))}
    </div>
  )
}

// Compact per-account "Unlink" button for the admin (readOnly) view. Confirms,
// then calls onUnlink(account) and reloads. Errors surface inline.
function UnlinkButton({ account, onUnlink }) {
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState('')
  async function go() {
    if (!window.confirm(`Unlink game account “${account}” from this user? Attribution stops immediately.`)) return
    setBusy(true); setError('')
    try {
      await onUnlink(account)
    } catch (err) {
      const byStatus = { 403: 'Protected account — refused.', 404: 'Not linked.' }
      setError(byStatus[err.status] || err.message || 'Could not unlink.')
      setBusy(false)
    }
  }
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
      <button type="button" onClick={go} disabled={busy} className="pill" style={{ fontSize: '0.72rem', color: '#d98b84', borderColor: '#5b2020' }}>
        {busy ? 'Unlinking…' : 'Unlink'}
      </button>
      {error && <span className="sans" style={{ color: '#d98b84', fontSize: '0.76rem' }}>{error}</span>}
    </span>
  )
}

export default function GameAccounts({ scope, charTo, readOnly = false, moderation = false, onUnlink = null }) {
  const [accounts, setAccounts] = useState(null)
  const [error, setError] = useState('')
  // Whether the site currently offers game-account creation (public flag). Only
  // relevant for the self-service (non-readOnly) view with a createAccount scope.
  const [signupOk, setSignupOk] = useState(false)

  const load = useCallback(async () => {
    setError('')
    try {
      setAccounts(await scope.accounts())
    } catch {
      setError(readOnly ? 'Could not load this user’s game accounts.' : 'Could not load your game accounts.')
    }
  }, [scope, readOnly])
  useEffect(() => { load() }, [load])

  useEffect(() => {
    if (readOnly || !scope.createAccount) return
    let active = true
    api.publicSettings()
      .then((s) => active && setSignupOk(Boolean(s?.gameAccountSignup)))
      .catch(() => {})
    return () => { active = false }
  }, [readOnly, scope])

  const canCreate = !readOnly && Boolean(scope.createAccount) && signupOk

  if (error) return <ErrorState message={error} />
  if (!accounts) return <Loading />

  // No linked accounts. In read-only (admin viewing another user) this is just an
  // empty state; otherwise it's the link-your-account prompt.
  if (accounts.length === 0) {
    if (readOnly) {
      return (
        <div className="panel" style={{ padding: 22 }}>
          <p className="sans dim" style={{ margin: 0, fontSize: '0.88rem' }}>
            This user has not linked a game account.
          </p>
        </div>
      )
    }
    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div className="panel" style={{ padding: 22 }}>
          <div className="field-label" style={{ marginBottom: 8 }}>Link your game account</div>
          <p className="sans" style={{ marginTop: 0, color: 'var(--muted)', fontSize: '0.88rem', lineHeight: 1.6 }}>
            Already play? In game, type <code style={{ color: 'var(--head)' }}>[link</code> to get a
            one-time code, then enter it below to see your characters, stats, skills and vendors here.
          </p>
          <LinkForm scope={scope} onLinked={load} />
        </div>
        {canCreate && (
          <div className="panel" style={{ padding: 22 }}>
            <div className="field-label" style={{ marginBottom: 8 }}>Create a new game account</div>
            <CreateGameAccountForm submit={scope.createAccount} onCreated={load} />
          </div>
        )}
      </div>
    )
  }

  // Linked — characters grouped by account.
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 26 }}>
      {accounts.map((a) => (
        <section key={a.account}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginBottom: 12 }}>
            <div className="sans" style={{ color: 'var(--accent)', fontSize: '0.7rem', letterSpacing: '0.12em', textTransform: 'uppercase' }}>
              {a.account}
            </div>
            {onUnlink && <UnlinkButton account={a.account} onUnlink={async (acct) => { await onUnlink(acct); await load() }} />}
          </div>
          {moderation && <ShardAccountActions account={a.account} style={{ marginBottom: 12 }} />}
          <AccountRoster scope={scope} account={a.account} charTo={charTo} />
        </section>
      ))}
      {!readOnly && (
        <section style={{ borderTop: '1px solid var(--line-soft)', paddingTop: 20 }}>
          <div className="field-label" style={{ marginBottom: 10 }}>Link another account</div>
          <LinkForm scope={scope} onLinked={load} compact />
          {canCreate && (
            <div style={{ marginTop: 20 }}>
              <div className="field-label" style={{ marginBottom: 10 }}>Create another game account</div>
              <CreateGameAccountForm submit={scope.createAccount} onCreated={load} compact />
            </div>
          )}
        </section>
      )}
    </div>
  )
}
