import { useState, useEffect, useRef } from 'react'
import { ExternalLink, Loader2, Check, Trash2 } from '../../../lib/icons'
import { Section, Row, Input, Toggle } from '../_ui'
import { useTrakt } from '../../../stores/trakt-store'
import { useWatchlist } from '../../../hooks/use-watchlist'
import { requestDeviceCode, pollDeviceToken, fetchTraktWatchlist } from '../../../lib/trakt'
import { toast } from '../../../stores/toast-store'
import { useLibraryByTmdbId } from '../../../hooks/use-jellyfin'

type Stage =
  | { kind: 'idle' }
  | { kind: 'pending'; userCode: string; verificationUrl: string }
  | { kind: 'success' }
  | { kind: 'error'; message: string }

export function TraktSection() {
  const clientId = useTrakt(s => s.clientId)
  const clientSecret = useTrakt(s => s.clientSecret)
  const tokens = useTrakt(s => s.tokens)
  const enabled = useTrakt(s => s.enabled)
  const setCredentials = useTrakt(s => s.setCredentials)
  const setEnabled = useTrakt(s => s.setEnabled)
  const setTokens = useTrakt(s => s.setTokens)
  const disconnect = useTrakt(s => s.disconnect)

  const [stage, setStage] = useState<Stage>({ kind: 'idle' })
  const cancelRef = useRef(false)
  const watchlist = useWatchlist()
  const libraryByTmdb = useLibraryByTmdbId()
  const [syncing, setSyncing] = useState(false)

  useEffect(() => () => { cancelRef.current = true }, [])

  async function syncWatchlistFromTrakt() {
    if (!tokens?.accessToken) {
      toast('Connect Trakt first', 'error')
      return
    }
    setSyncing(true)
    try {
      const traktItems = await fetchTraktWatchlist()
      let added = 0
      for (const t of traktItems) {
        const tmdbId = t.ids.tmdb ? String(t.ids.tmdb) : null
        if (!tmdbId) continue
        const local = libraryByTmdb.data?.get(tmdbId)
        if (local?.id && watchlist.playlistId) {
          await watchlist.addToWatchlist(local.id)
          added++
        }
      }
      toast(`Synced ${added} items from Trakt watchlist`, 'success')
    } catch {
      toast('Sync failed', 'error')
    } finally {
      setSyncing(false)
    }
  }

  async function startDeviceFlow() {
    if (!clientId || !clientSecret) {
      toast('Add your Trakt client ID and secret first', 'error')
      return
    }
    cancelRef.current = false
    setStage({ kind: 'idle' })
    try {
      const code = await requestDeviceCode()
      setStage({ kind: 'pending', userCode: code.user_code, verificationUrl: code.verification_url })
      const deadline = Date.now() + code.expires_in * 1000
      const interval = Math.max(2, code.interval) * 1000
      while (!cancelRef.current && Date.now() < deadline) {
        await new Promise(r => setTimeout(r, interval))
        if (cancelRef.current) return
        try {
          const tok = await pollDeviceToken(code.device_code)
          if (tok) {
            setTokens({
              accessToken: tok.access_token,
              refreshToken: tok.refresh_token,
              expiresAt: new Date(Date.now() + tok.expires_in * 1000).toISOString(),
            })
            setStage({ kind: 'success' })
            toast('Trakt connected', 'success')
            return
          }
        } catch (err: any) {
          setStage({ kind: 'error', message: err?.message || 'Authorisation failed' })
          return
        }
      }
      if (!cancelRef.current) {
        setStage({ kind: 'error', message: 'Code expired - try again' })
      }
    } catch (err: any) {
      setStage({ kind: 'error', message: err?.message || 'Could not start authorisation' })
    }
  }

  function cancelFlow() {
    cancelRef.current = true
    setStage({ kind: 'idle' })
  }

  const connected = !!tokens

  return (
    <Section
      id="trakt"
      title="Trakt.tv"
      description="Scrobble what you watch to Trakt.tv to keep your history and ratings in sync"
    >
      <Row label="Enable scrobbling" hint="Send start, pause, and stop events while watching">
        <Toggle value={enabled} onChange={setEnabled} />
      </Row>
      <Row label="Client ID" hint="From trakt.tv/oauth/applications">
        <Input
          value={clientId}
          onChange={v => setCredentials(v, clientSecret)}
          placeholder="abc123..."
          width="w-64"
        />
      </Row>
      <Row label="Client Secret" hint="Stays on this device">
        <Input
          type="password"
          value={clientSecret}
          onChange={v => setCredentials(clientId, v)}
          placeholder="def456..."
          width="w-64"
        />
      </Row>

      {connected ? (
        <>
          <Row label="Connection" hint="Currently signed in to Trakt">
            <button
              onClick={() => {
                disconnect()
                toast('Disconnected from Trakt', 'info')
              }}
              className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-elevated/60 text-text-2 border border-border hover:border-error/50 hover:text-error transition-all duration-150 focus-ring"
            >
              <Trash2 size={13} stroke={2} />
              Disconnect
            </button>
          </Row>
          <Row label="Sync watchlist" hint="Pull items from your Trakt watchlist into the local watchlist">
            <button
              onClick={syncWatchlistFromTrakt}
              disabled={syncing}
              className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-accent hover:bg-accent-hover text-void disabled:opacity-40 transition-colors focus-ring"
            >
              {syncing ? <Loader2 size={13} stroke={2} className="animate-[spin-soft_1s_linear_infinite]" /> : <Check size={13} stroke={2} />}
              {syncing ? 'Syncing...' : 'Sync now'}
            </button>
          </Row>
        </>
      ) : (
        <Row label="Connect" hint="Authorise this app to scrobble on your behalf">
          {stage.kind === 'pending' ? (
            <div className="flex items-center gap-2">
              <span className="text-[12px] text-text-2 tabular-nums font-mono">
                Code: <span className="font-bold text-accent">{stage.userCode}</span>
              </span>
              <a
                href={stage.verificationUrl}
                target="_blank"
                rel="noopener noreferrer"
                className="inline-flex items-center gap-1 text-[12px] text-accent hover:text-accent-hover font-medium"
              >
                Open
                <ExternalLink size={11} />
              </a>
              <button
                onClick={cancelFlow}
                className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-elevated/60 text-text-2 border border-border hover:border-border-hover hover:text-text-1 transition-all duration-150 focus-ring"
              >
                Cancel
              </button>
            </div>
          ) : (
            <button
              onClick={startDeviceFlow}
              disabled={!clientId || !clientSecret}
              className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-accent hover:bg-accent-hover text-void disabled:opacity-40 disabled:cursor-not-allowed transition-colors focus-ring"
            >
              {stage.kind === 'success' ? <Check size={13} stroke={2} /> : <Loader2 size={13} stroke={2} className="hidden" />}
              Connect
            </button>
          )}
        </Row>
      )}

      {stage.kind === 'error' && (
        <p className="px-1 py-2 text-[11.5px] text-error/95 leading-snug">
          {stage.message}
        </p>
      )}

      <div className="py-3 -mx-4 px-4 text-[11.5px] text-text-3 flex items-center justify-between gap-4 border-t border-border/50">
        <span>Need an app?</span>
        <a
          href="https://trakt.tv/oauth/applications"
          target="_blank"
          rel="noopener noreferrer"
          className="inline-flex items-center gap-1 text-accent hover:text-accent-hover transition-colors font-medium"
        >
          Create one on Trakt
          <ExternalLink size={11} />
        </a>
      </div>
    </Section>
  )
}
