import { useCallback, useEffect, useReducer, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { api, ApiError } from '../api.js'
import CandidateCard from '../components/CandidateCard.js'
import ConfirmView from '../scan/ConfirmView.js'
import Cover from '../components/Cover.js'
import { scanReducer, INITIAL_SCAN_STATE, type ScanErrorKind } from '../scan/reducer.js'

function toErrorKind(err: unknown): ScanErrorKind {
  if (err instanceof ApiError) {
    if (err.code === 'not_found') return 'not_found'
    if (err.code === 'no_discogs_token') return 'no_discogs_token'
    if (err.code === 'discogs_auth') return 'discogs_auth'
    if (err.code === 'discogs_rate_limited' || err.status === 429) return 'rate_limited'
  }
  return 'server'
}

const FORMATS = ['Vinyl', 'CD', 'Cassette'] as const

export default function AddPage() {
  const [params] = useSearchParams()
  const [q, setQ] = useState(params.get('q') ?? '')
  const [format, setFormat] = useState<(typeof FORMATS)[number] | ''>('')
  const [state, dispatch] = useReducer(scanReducer, INITIAL_SCAN_STATE)

  const search = useCallback(
    (query: string) => {
      if (!query.trim()) return
      dispatch({ type: 'DETECT', code: query.trim() })
      void (async () => {
        try {
          const { candidates } = await api.lookupSearch(query.trim(), format || undefined)
          if (candidates.length === 0) {
            dispatch({ type: 'NOT_FOUND', code: query.trim() })
          } else {
            dispatch({ type: 'CANDIDATES', code: query.trim(), candidates })
          }
        } catch (err) {
          dispatch({ type: 'ERROR', kind: toErrorKind(err), code: query.trim(), source: 'lookup' })
        }
      })()
    },
    [format]
  )

  // Load the release preview once a candidate is selected.
  useEffect(() => {
    if (state.phase !== 'confirm' || state.preview) return
    const candidateId = state.candidate.id
    void (async () => {
      try {
        const preview = await api.getReleasePreview(candidateId)
        dispatch({ type: 'PREVIEW', preview, candidateId })
      } catch (err) {
        dispatch({ type: 'ERROR', kind: toErrorKind(err), code: null, source: 'preview', candidateId })
      }
    })()
  }, [state])

  const add = useCallback(() => {
    if (state.phase !== 'confirm' || !state.preview || state.adding) return
    const { candidate, matchAlbumId } = state
    dispatch({ type: 'ADD_START' })
    void (async () => {
      try {
        const item = await api.addToCollection({
          releaseId: candidate.id,
          ...(matchAlbumId !== null ? { matchAlbumId } : {}),
        })
        dispatch({ type: 'ADDED', item })
      } catch (err) {
        const message =
          err instanceof ApiError
            ? err.code === 'duplicate'
              ? 'Already in your collection.'
              : err.detail ?? err.code
            : 'Something went wrong'
        dispatch({ type: 'ADD_ERROR', message })
      }
    })()
  }, [state])

  return (
    <div className="space-y-4">
      {state.phase === 'scan' && (
        <form
          onSubmit={(e) => {
            e.preventDefault()
            search(q)
          }}
          className="space-y-3"
        >
          <input
            value={q}
            onChange={(e) => setQ(e.target.value)}
            placeholder="Artist and title"
            className="w-full rounded-xl border border-neutral-800 bg-neutral-900 px-3 py-2 text-sm"
          />
          <div className="flex gap-2">
            <label className="sr-only" htmlFor="format">
              Format
            </label>
            <select
              id="format"
              value={format}
              onChange={(e) => setFormat(e.target.value as (typeof FORMATS)[number] | '')}
              className="rounded-xl border border-neutral-800 bg-neutral-900 px-3 py-2 text-sm"
            >
              <option value="">Any format</option>
              {FORMATS.map((f) => (
                <option key={f} value={f}>
                  {f}
                </option>
              ))}
            </select>
            <button type="submit" className="flex-1 rounded-xl bg-emerald-500 py-2 font-medium text-neutral-950">
              Search
            </button>
          </div>
          <Link to="/scan" className="block text-center text-sm text-neutral-400">
            or scan a barcode →
          </Link>
        </form>
      )}

      {state.phase === 'looking' && <p className="py-8 text-center text-neutral-400">Searching…</p>}

      {state.phase === 'candidates' && (
        <div className="space-y-3">
          <p className="text-sm text-neutral-400">Which release is it?</p>
          {state.candidates.map((c) => (
            <CandidateCard key={c.id} candidate={c} onSelect={(cand) => dispatch({ type: 'SELECT', candidate: cand })} />
          ))}
        </div>
      )}

      {state.phase === 'confirm' && (
        <div className="space-y-4">
          {!state.preview && <p className="py-8 text-center text-neutral-400">Checking release…</p>}
          {state.preview && (
            <ConfirmView
              code={null}
              preview={state.preview}
              matchAlbumId={state.matchAlbumId}
              onSetMatch={(albumId) => dispatch({ type: 'SET_MATCH', albumId })}
              onClearMatch={() => dispatch({ type: 'CLEAR_MATCH' })}
              onAdd={add}
              adding={state.adding}
              addError={state.addError}
            />
          )}
          <button
            type="button"
            onClick={() => dispatch({ type: 'RESET' })}
            className="w-full rounded-xl border border-neutral-700 py-2 text-sm text-neutral-300"
          >
            Back to search
          </button>
        </div>
      )}

      {state.phase === 'added' && (
        <div className="space-y-4 text-center">
          <Cover src={state.item.artworkUrl} alt="" className="mx-auto size-32" />
          <p className="text-lg font-medium">Added to collection ✓</p>
          <Link className="block text-sm text-emerald-400" to={`/item/${state.item.id}`}>
            View item
          </Link>
          <button
            type="button"
            onClick={() => dispatch({ type: 'RESET' })}
            className="w-full rounded-xl border border-neutral-700 py-2 text-sm text-neutral-300"
          >
            Add another
          </button>
        </div>
      )}

      {state.phase === 'error' && (
        <div className="space-y-3 py-8 text-center">
          <p className="text-lg font-medium">
            {state.kind === 'not_found'
              ? 'Nothing found'
              : state.kind === 'discogs_auth'
                ? 'Discogs rejected your token'
                : 'Search failed'}
          </p>
          <p className="text-sm text-neutral-400">
            {state.kind === 'not_found' && 'Try different spelling, or add the year.'}
            {state.kind === 'no_discogs_token' && 'Add your Discogs token in Settings first.'}
            {state.kind === 'discogs_auth' && 'Check your Discogs token in Settings.'}
            {state.kind === 'rate_limited' && 'Discogs is rate limiting us. Try again shortly.'}
          </p>
          <button
            type="button"
            onClick={() => dispatch({ type: 'RESET' })}
            className="rounded-xl border border-neutral-700 px-4 py-2 text-sm text-neutral-300"
          >
            Back
          </button>
        </div>
      )}
    </div>
  )
}
