import { useCallback, useState } from 'react'
import { Link } from 'react-router-dom'
import { Loading, ErrorState } from '../../components/PageState.jsx'
import { useAsync } from '../../lib/useAsync.js'
import { ago, dateTime } from '../../lib/format.js'
import { api } from '../../api/client.js'

// Player-facing appeals: eligible sanctions the player can appeal, plus the
// status of appeals they've already submitted. Mirrors PlayerAccount's
// Section layout.

const STATUS_STYLE = {
  pending: { color: '#e0b070', background: 'rgba(224,176,112,0.12)', border: '1px solid rgba(224,176,112,0.4)' },
  under_review: { color: '#7fa8d0', background: 'rgba(127,168,208,0.14)', border: '1px solid rgba(127,168,208,0.4)' },
  approved: { color: '#7fd0a4', background: 'rgba(95,185,138,0.16)', border: '1px solid rgba(95,185,138,0.4)' },
  denied: { color: '#d98b84', background: 'rgba(217,139,132,0.16)', border: '1px solid rgba(217,139,132,0.4)' },
  withdrawn: { color: '#9fb0c6', background: 'rgba(127,153,189,0.14)', border: '1px solid var(--line)' },
}
const STATUS_LABEL = {
  pending: 'Pending',
  under_review: 'Under review',
  approved: 'Approved',
  denied: 'Denied',
  withdrawn: 'Withdrawn',
}

function fmtDuration(seconds) {
  if (!seconds) return null
  if (seconds % 86400 === 0) return `${seconds / 86400}d`
  if (seconds % 3600 === 0) return `${seconds / 3600}h`
  if (seconds % 60 === 0) return `${seconds / 60}m`
  return `${seconds}s`
}

function Section({ title, children }) {
  return (
    <section style={{ borderTop: '1px solid var(--line-soft)', paddingTop: 26, marginTop: 26 }}>
      <h2 className="display" style={{ marginTop: 0, fontSize: '1.15rem', color: 'var(--head)' }}>{title}</h2>
      {children}
    </section>
  )
}

function EligibleItem({ item, onSubmitted }) {
  const [open, setOpen] = useState(false)
  const [text, setText] = useState('')
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState('')

  async function submit() {
    if (!text.trim()) return
    setBusy(true)
    setError('')
    try {
      await api.player.submitAppeal({ mod_action_id: item.id, submitted_text: text.trim() })
      setText('')
      setOpen(false)
      onSubmitted()
    } catch (err) {
      setError(err.message || 'Could not submit your appeal.')
    } finally {
      setBusy(false)
    }
  }

  const duration = fmtDuration(item.duration_seconds)

  return (
    <div className="panel" style={{ padding: '14px 16px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <span className={`badge badge-${item.action_type}`}>{item.action_type}</span>
        {duration && <span className="sans dim" style={{ fontSize: '0.78rem' }}>{duration}</span>}
        <span className="sans dim" style={{ fontSize: '0.78rem', marginLeft: 'auto' }} title={dateTime(item.created_at)}>
          {ago(item.created_at)}
        </span>
      </div>
      <p className="sans" style={{ margin: '10px 0 0', color: 'var(--text)', fontSize: '0.88rem' }}>
        {item.reason || 'No reason given.'}
      </p>

      {!open ? (
        <div style={{ marginTop: 12 }}>
          <button onClick={() => setOpen(true)} className="btn btn-primary btn-sq">
            Appeal this
          </button>
        </div>
      ) : (
        <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
          {error && <p className="sans" style={{ margin: 0, color: '#d98b84', fontSize: '0.85rem' }}>{error}</p>}
          <textarea
            className="textarea"
            placeholder="Explain why this action should be reversed…"
            value={text}
            onChange={(e) => setText(e.target.value)}
            rows={4}
            style={{ width: '100%' }}
          />
          <div style={{ display: 'flex', gap: 10 }}>
            <button onClick={submit} disabled={busy || !text.trim()} className="btn btn-primary btn-sq">
              {busy ? 'Submitting…' : 'Submit appeal'}
            </button>
            <button onClick={() => { setOpen(false); setError('') }} disabled={busy} className="pill">
              Cancel
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

function EligibleAppeals({ items, onSubmitted }) {
  if (items.length === 0) {
    return (
      <div>
        <p className="sans dim" style={{ fontSize: '0.88rem' }}>You have no sanctions available to appeal right now.</p>
        <p className="sans dim" style={{ fontSize: '0.82rem' }}>
          If you were sanctioned on Discord, link your Discord account on the{' '}
          <Link to="/account" className="link-accent">Account</Link> page to appeal.
        </p>
      </div>
    )
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {items.map((item) => (
        <EligibleItem key={item.id} item={item} onSubmitted={onSubmitted} />
      ))}
    </div>
  )
}

function MyAppealItem({ appeal, onWithdrawn }) {
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState('')
  const canWithdraw = appeal.status === 'pending' || appeal.status === 'under_review'

  async function withdraw() {
    setBusy(true)
    setError('')
    try {
      await api.player.withdrawAppeal(appeal.id)
      onWithdrawn()
    } catch (err) {
      setError(err.message || 'Could not withdraw this appeal.')
      setBusy(false)
    }
  }

  return (
    <div className="panel" style={{ padding: '14px 16px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <span className={`badge badge-${appeal.action_type}`}>{appeal.action_type}</span>
        <span className="badge" style={STATUS_STYLE[appeal.status]}>{STATUS_LABEL[appeal.status] || appeal.status}</span>
        <span className="sans dim" style={{ fontSize: '0.78rem', marginLeft: 'auto' }} title={dateTime(appeal.submitted_at)}>
          {ago(appeal.submitted_at)}
        </span>
      </div>
      <p className="sans" style={{ margin: '10px 0 0', color: 'var(--text)', fontSize: '0.88rem', whiteSpace: 'pre-wrap' }}>
        {appeal.submitted_text}
      </p>
      {appeal.staff_response && (
        <div style={{ marginTop: 10, padding: '10px 12px', border: '1px solid var(--line)', borderRadius: 8 }}>
          <div className="field-label" style={{ marginBottom: 4 }}>Staff response</div>
          <p className="sans dim" style={{ margin: 0, fontSize: '0.86rem', whiteSpace: 'pre-wrap' }}>{appeal.staff_response}</p>
        </div>
      )}
      {error && <p className="sans" style={{ margin: '10px 0 0', color: '#d98b84', fontSize: '0.85rem' }}>{error}</p>}
      {canWithdraw && (
        <div style={{ marginTop: 12 }}>
          <button onClick={withdraw} disabled={busy} className="pill" style={{ color: '#d98b84', borderColor: '#d98b84' }}>
            {busy ? 'Withdrawing…' : 'Withdraw'}
          </button>
        </div>
      )}
    </div>
  )
}

function MyAppeals({ appeals, onChange }) {
  if (appeals.length === 0) {
    return <p className="sans dim" style={{ fontSize: '0.88rem' }}>You haven't submitted any appeals yet.</p>
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {appeals.map((a) => (
        <MyAppealItem key={a.id} appeal={a} onWithdrawn={onChange} />
      ))}
    </div>
  )
}

export default function PlayerAppeals() {
  const [tick, setTick] = useState(0)
  const reload = useCallback(() => setTick((t) => t + 1), [])
  const { loading, error, data } = useAsync(
    () => Promise.all([api.player.getEligibleAppeals(), api.player.getMyAppeals()]),
    [tick],
  )

  if (loading) return <Loading />
  if (error) return <ErrorState message="Could not load your appeals." />

  const [eligible, mine] = data

  return (
    <div>
      <p className="sans" style={{ margin: 0, color: 'var(--muted)', fontSize: '0.9rem' }}>
        Appeal a Discord ban or mute, or check the status of an appeal you've already submitted.
      </p>

      <Section title="Appealable sanctions">
        <EligibleAppeals items={eligible} onSubmitted={reload} />
      </Section>

      <Section title="My appeals">
        <MyAppeals appeals={mine} onChange={reload} />
      </Section>
    </div>
  )
}
