/**
 * BoostMedia AI Content Generator Admin - Jobs Page
 *
 * Active jobs tracking with polling, history, and summary.
 *
 * @package BoostMedia_AI
 * @license GPL-2.0-or-later
 */

import { useState, useEffect, useCallback, useRef } from 'react'
import { useNavigate } from 'react-router-dom'
import {
  Activity,
  FileText,
  Coins,
  Repeat,
  RefreshCw,
  FlaskConical,
  PenTool,
  CheckCircle,
  XCircle,
  Clock,
  ArrowRight,
  Eye,
  Play,
  AlertCircle,
  CalendarClock,
} from 'lucide-react'
import { Header } from '../components/layout/Header'
import { Card, CardContent, Badge, Button } from '../components/common'
import { endpoints } from '../api/client'
import type { JobListItem, JobSummary, UpcomingPlan } from '../types'
import { t, tf, getDateLocale } from '../lib/i18n'

function formatRelativeTime(dateStr: string): string {
  const date = new Date(dateStr)
  const now = new Date()
  const diffMs = now.getTime() - date.getTime()
  const diffMinutes = Math.floor(diffMs / 60000)
  const diffHours = Math.floor(diffMs / 3600000)
  const diffDays = Math.floor(diffMs / 86400000)

  if (diffMinutes < 1) return t('just now')
  if (diffMinutes < 60) return tf('%d minutes ago', diffMinutes)
  if (diffHours < 24) return tf('%d hours ago', diffHours)
  if (diffDays < 7) return tf('%d days ago', diffDays)
  return date.toLocaleDateString(getDateLocale(), { day: 'numeric', month: 'short', year: 'numeric' })
}

function formatDuration(startStr: string, endStr?: string | null): string {
  const start = new Date(startStr)
  const end = endStr ? new Date(endStr) : new Date()
  const diffMs = end.getTime() - start.getTime()
  const seconds = Math.floor(diffMs / 1000)
  const minutes = Math.floor(seconds / 60)
  const hours = Math.floor(minutes / 60)

  if (hours > 0) return `${hours}h ${minutes % 60}m`
  if (minutes > 0) return `${minutes}m ${seconds % 60}s`
  return tf('%d seconds', seconds)
}

function formatNextRun(dateStr: string | null): string {
  if (!dateStr) return ''
  const date = new Date(dateStr)
  const now = new Date()
  const diffMs = date.getTime() - now.getTime()
  const diffHours = Math.floor(diffMs / 3600000)
  const diffDays = Math.floor(diffMs / 86400000)

  if (diffMs < 0) return t('Overdue')
  if (diffHours < 1) return t('Less than 1 hour')
  if (diffHours < 24) return tf('%d hours', diffHours)
  if (diffDays < 7) return tf('%d days', diffDays)
  return date.toLocaleDateString(getDateLocale(), { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })
}

function jobStatusBadge(status: string) {
  switch (status) {
    case 'queued':
      return <Badge variant="default" dot>{t('Queued')}</Badge>
    case 'processing':
    case 'running':
    case 'forming_articles':
      return <Badge variant="info" dot>{t('In Progress')}</Badge>
    case 'complete':
    case 'completed':
    case 'delivered':
      return <Badge variant="success" dot>{t('Completed')}</Badge>
    case 'failed':
      return <Badge variant="error" dot>{t('Failed')}</Badge>
    default:
      return <Badge variant="default">{status}</Badge>
  }
}

function SummaryCard({ icon: Icon, value, label }: { icon: typeof Activity; value: string | number; label: string }) {
  return (
    <Card>
      <CardContent className="flex items-center gap-4 py-4">
        <div className="w-10 h-10 rounded-bc bg-bc-primary-light flex items-center justify-center shrink-0">
          <Icon className="w-5 h-5 text-bc-primary" />
        </div>
        <div>
          <div className="text-2xl font-bold text-bc-gray-800 tabular-nums">{value}</div>
          <div className="text-xs text-bc-gray-500">{label}</div>
        </div>
      </CardContent>
    </Card>
  )
}

function ActiveJobCard({ job, onView }: { job: JobListItem; onView: (job: JobListItem) => void }) {
  const isSprint = job.type === 'sprint'
  const progress = job.articles_total > 0
    ? Math.round((job.articles_completed / job.articles_total) * 100)
    : 0

  return (
    <div className="border border-bc-gray-200 rounded-bc p-4 mb-3 last:mb-0">
      <div className="flex items-start justify-between gap-3">
        <div className="flex items-center gap-3 min-w-0">
          <div className={`w-8 h-8 rounded-bc flex items-center justify-center shrink-0 ${
            isSprint ? 'bg-violet-50' : 'bg-blue-50'
          }`}>
            {isSprint
              ? <FlaskConical className="w-4 h-4 text-violet-600" />
              : <PenTool className="w-4 h-4 text-blue-600" />
            }
          </div>
          <div className="min-w-0">
            <div className="font-medium text-bc-gray-800 truncate">
              {job.plan_name || (isSprint ? t('Research Sprint') : t('Article Generation'))}
            </div>
            <div className="text-xs text-bc-gray-500 mt-0.5">
              {isSprint ? t('Research Sprint') : t('Article Generation')}
              {job.execution_type === 'scheduled' && (
                <span className="ms-2 px-1.5 py-0.5 bg-blue-50 text-blue-600 rounded text-xs">
                  {t('Scheduled')}
                </span>
              )}
              {job.status === 'running' && job.rounds_max > 0 && (
                <span className="ms-2">{tf('Round %d of %d', job.rounds_used, job.rounds_max)}</span>
              )}
              {job.findings_count > 0 && (
                <span className="ms-2">{tf('%d findings', job.findings_count)}</span>
              )}
            </div>
          </div>
        </div>
        <div className="flex items-center gap-2 shrink-0">
          {jobStatusBadge(job.status)}
          <Button variant="ghost" size="sm" onClick={() => onView(job)}>
            <Eye className="w-4 h-4" />
          </Button>
        </div>
      </div>

      {job.articles_total > 0 && (
        <div className="mt-3">
          <div className="flex justify-between text-xs text-bc-gray-500 mb-1">
            <span>{tf('Article %d of %d', job.articles_completed, job.articles_total)}</span>
            <span>{progress}%</span>
          </div>
          <div className="h-2 bg-bc-gray-100 rounded-full overflow-hidden">
            <div
              className="h-full rounded-full bg-bc-primary transition-all duration-500"
              style={{ width: `${progress}%` }}
            />
          </div>
        </div>
      )}

      <div className="flex items-center gap-4 mt-3 text-xs text-bc-gray-400">
        <span className="flex items-center gap-1">
          <Clock className="w-3 h-3" />
          {formatDuration(job.started_at)}
        </span>
        {job.cost_coins > 0 && (
          <span className="flex items-center gap-1">
            <Coins className="w-3 h-3" />
            {job.cost_coins.toFixed(1)} BC
          </span>
        )}
      </div>
    </div>
  )
}

function HistoryJobCard({ job, onView, onRunAgain }: {
  job: JobListItem
  onView: (job: JobListItem) => void
  onRunAgain: (job: JobListItem) => void
}) {
  const isSprint = job.type === 'sprint'
  const isComplete = job.status === 'complete' || job.status === 'completed' || job.status === 'delivered'
  const isFailed = job.status === 'failed'

  return (
    <div className="border border-bc-gray-200 rounded-bc p-4 mb-3 last:mb-0">
      <div className="flex items-start justify-between gap-3">
        <div className="flex items-center gap-3 min-w-0">
          <div className={`w-8 h-8 rounded-bc flex items-center justify-center shrink-0 ${
            isComplete ? 'bg-green-50' : isFailed ? 'bg-red-50' : 'bg-bc-gray-50'
          }`}>
            {isComplete
              ? <CheckCircle className="w-4 h-4 text-green-600" />
              : isFailed
                ? <XCircle className="w-4 h-4 text-red-600" />
                : <Clock className="w-4 h-4 text-bc-gray-400" />
            }
          </div>
          <div className="min-w-0">
            <div className="font-medium text-bc-gray-800 truncate">
              {isComplete
                ? (job.articles_completed === 1
                    ? t('Created 1 article')
                    : tf('Created %d articles', job.articles_completed))
                : isFailed
                  ? (job.type === 'sprint'
                      ? t('Sprint failed')
                      : job.type === 'generation'
                        ? t('Generation failed')
                        : t('Job failed'))
                  : job.plan_name || t('Article Generation')
              }
            </div>
            <div className="text-xs text-bc-gray-500 mt-0.5 truncate">
              {job.plan_name ? <span>{job.plan_name}</span> : null}
              {job.execution_type === 'scheduled' && (
                <span className="ms-2 px-1.5 py-0.5 bg-blue-50 text-blue-600 rounded text-xs">
                  {t('Scheduled')}
                </span>
              )}
              {job.execution_type === 'one_time' && (
                <span className="ms-2 px-1.5 py-0.5 bg-bc-gray-50 text-bc-gray-500 rounded text-xs">
                  {t('One-time')}
                </span>
              )}
              {isFailed && job.error_message && (
                <span className="text-red-500 ms-1">{job.error_message}</span>
              )}
            </div>
          </div>
        </div>
        <div className="flex items-center gap-2 shrink-0">
          {jobStatusBadge(job.status)}
        </div>
      </div>

      <div className="flex items-center justify-between mt-3">
        <div className="flex items-center gap-4 text-xs text-bc-gray-400">
          {job.started_at && (
            <span className="flex items-center gap-1">
              <Clock className="w-3 h-3" />
              {formatRelativeTime(job.started_at)}
            </span>
          )}
          {job.completed_at && job.started_at && (
            <span>{formatDuration(job.started_at, job.completed_at)}</span>
          )}
          {job.cost_coins > 0 && (
            <span className="flex items-center gap-1">
              <Coins className="w-3 h-3" />
              {job.cost_coins.toFixed(1)} BC
            </span>
          )}
          {isSprint && (
            <>
              {job.rounds_used > 0 && (
                <span>{tf('Round %d of %d', job.rounds_used, job.rounds_max)}</span>
              )}
              {job.findings_count > 0 && (
                <span>{tf('%d findings', job.findings_count)}</span>
              )}
            </>
          )}
        </div>
        <div className="flex items-center gap-1">
          {isComplete && (
            <>
              <Button variant="ghost" size="sm" onClick={() => onView(job)} icon={<Eye className="w-3.5 h-3.5" />}>
                {t('View articles')}
              </Button>
              {job.plan_id ? (
                <Button variant="ghost" size="sm" onClick={() => onRunAgain(job)} icon={<Play className="w-3.5 h-3.5" />}>
                  {t('Run again')}
                </Button>
              ) : null}
            </>
          )}
          {isFailed && job.plan_id ? (
            <Button variant="ghost" size="sm" onClick={() => onRunAgain(job)} icon={<RefreshCw className="w-3.5 h-3.5" />}>
              {t('Try again')}
            </Button>
          ) : null}
        </div>
      </div>
    </div>
  )
}

type FilterStatus = 'all' | 'complete' | 'failed'

export default function JobsPage() {
  const navigate = useNavigate()
  const [allJobs, setAllJobs] = useState<JobListItem[]>([])
  const [activeJobs, setActiveJobs] = useState<JobListItem[]>([])
  const [upcomingPlans, setUpcomingPlans] = useState<UpcomingPlan[]>([])
  const [summary, setSummary] = useState<JobSummary>({ active_count: 0, completed_today: 0, articles_today: 0, coins_today: 0 })
  const [filter, setFilter] = useState<FilterStatus>('all')
  const [loading, setLoading] = useState(true)
  const [refreshing, setRefreshing] = useState(false)
  const [nextCursor, setNextCursor] = useState<string | null>(null)
  const [hasMore, setHasMore] = useState(false)
  const mountedRef = useRef(true)

  const PAGE_SIZE = 20
  const prevActiveIdsRef = useRef<Set<string>>(new Set())

  const loadUpcomingPlans = useCallback(async () => {
    try {
      const result = await endpoints.getUpcomingPlans()
      if (!mountedRef.current) return
      setUpcomingPlans(result.data ?? [])
    } catch {
      // silently ignore
    }
  }, [])

  const loadJobs = useCallback(async (showLoader = false) => {
    if (showLoader) setLoading(true)
    try {
      const [jobsResult] = await Promise.all([
        endpoints.listJobs({ limit: PAGE_SIZE, status: 'all' }),
        loadUpcomingPlans(),
      ])
      if (!mountedRef.current) return
      const data = jobsResult.data
      setAllJobs(data.jobs)
      setNextCursor(data.next_cursor ?? null)
      setHasMore(data.has_more ?? false)
      const active = data.jobs.filter(j => ['queued', 'running', 'forming_articles', 'processing'].includes(j.status))
      setActiveJobs(active)
      prevActiveIdsRef.current = new Set(active.map(j => j.id))
      setSummary(data.summary)
    } catch {
      // silently ignore
    } finally {
      if (mountedRef.current) setLoading(false)
    }
  }, [loadUpcomingPlans])

  const pollActive = useCallback(async () => {
    try {
      const result = await endpoints.listJobs({ status: 'active', limit: 50 })
      if (!mountedRef.current) return
      const data = result.data
      const freshActive = data.jobs
      setActiveJobs(freshActive)
      setSummary(data.summary)

      setAllJobs(prev => {
        const activeMap = new Map(freshActive.map(j => [j.id, j]))
        return prev.map(job => activeMap.get(job.id) || job)
      })

      const freshIds = new Set(freshActive.map(j => j.id))
      const prevIds = prevActiveIdsRef.current
      const newlyCompleted = [...prevIds].filter(id => !freshIds.has(id))
      prevActiveIdsRef.current = freshIds

      if (newlyCompleted.length > 0) {
        loadJobs(false)
      }
    } catch {
      // silently ignore
    }
  }, [loadJobs])

  useEffect(() => {
    mountedRef.current = true
    loadJobs(true)
    const poll = setInterval(pollActive, 10000)
    return () => {
      mountedRef.current = false
      clearInterval(poll)
    }
  }, [loadJobs, pollActive])

  const loadMore = async () => {
    if (!nextCursor) return
    try {
      const result = await endpoints.listJobs({ limit: PAGE_SIZE, before: nextCursor, status: filter === 'all' ? 'all' : filter })
      if (!mountedRef.current) return
      const data = result.data
      const newJobs = data.jobs
      setAllJobs(prev => {
        const existingIds = new Set(prev.map(j => j.id))
        const unique = newJobs.filter(j => !existingIds.has(j.id))
        return [...prev, ...unique]
      })
      setNextCursor(data.next_cursor ?? null)
      setHasMore(data.has_more ?? false)
    } catch {
      // silently ignore
    }
  }

  const handleRefresh = async () => {
    setRefreshing(true)
    await loadJobs(false)
    setRefreshing(false)
  }

  const handleFilterChange = async (newFilter: FilterStatus) => {
    setFilter(newFilter)
    setLoading(true)
    try {
      const status = newFilter === 'all' ? 'all' : newFilter
      const result = await endpoints.listJobs({ limit: PAGE_SIZE, status })
      if (!mountedRef.current) return
      const data = result.data
      setAllJobs(data.jobs)
      setNextCursor(data.next_cursor ?? null)
      setHasMore(data.has_more ?? false)
    } catch {
      // silently ignore
    } finally {
      if (mountedRef.current) setLoading(false)
    }
  }

  const handleView = (job: JobListItem) => {
    const isComplete = ['complete', 'completed', 'delivered'].includes(job.status)
    if (isComplete) {
      const planParam = job.plan_id ? `?planId=${job.plan_id}` : ''
      navigate(`/generated${planParam}`)
    } else {
      navigate(`/generate?planId=${job.plan_id}&intent=review&step=settings`)
    }
  }

  const handleRunAgain = (job: JobListItem) => {
    if (job.plan_id != null && job.plan_id > 0) {
      navigate(`/generate?planId=${job.plan_id}&intent=review&step=settings`)
    }
  }

  const historyJobs = allJobs.filter(j => {
    const isActive = ['queued', 'running', 'forming_articles', 'processing'].includes(j.status)
    if (isActive) return false
    if (filter === 'complete') return ['complete', 'completed', 'delivered'].includes(j.status)
    if (filter === 'failed') return j.status === 'failed'
    return true
  })

  const canLoadMore = hasMore && !!nextCursor

  if (loading && allJobs.length === 0) {
    return (
      <div className="min-h-screen">
        <Header title={t('Jobs')} subtitle={t('Track all running and completed generation jobs')} />
        <div className="flex items-center justify-center p-12">
          <RefreshCw className="w-6 h-6 animate-spin text-bc-primary" />
          <span className="ms-3 text-bc-gray-600">{t('Loading...')}</span>
        </div>
      </div>
    )
  }

  return (
    <div className="min-h-screen">
      <Header
        title={t('Jobs')}
        subtitle={t('Track all running and completed generation jobs')}
        onRefresh={handleRefresh}
        isRefreshing={refreshing}
        helpContent={[
          t('The Jobs page tracks all content generation activity.'),
          t('Active jobs show research and generation progress in real time.'),
          t('Completed jobs show article count, cost, and duration.'),
          t('Scheduled plans appear greyed out with their next run time.'),
          t('Click "View articles" on any completed job to review the generated content.'),
        ]}
      />

      <div className="p-6 space-y-6">
        {/* Summary Cards */}
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
          <SummaryCard icon={Activity} value={summary.active_count} label={t('Active jobs')} />
          <SummaryCard icon={FileText} value={summary.articles_today} label={t('Articles today')} />
          <SummaryCard
            icon={Coins}
            value={summary.coins_today > 0 ? summary.coins_today.toFixed(1) : '0'}
            label={t('BoostCoins today')}
          />
          <SummaryCard icon={Repeat} value={summary.completed_today} label={t('Completed today')} />
        </div>

        {/* Scheduled Plans */}
        {upcomingPlans.length > 0 && (
          <Card padding="none">
            <CardContent className="p-6">
              <div className="flex items-center gap-3 mb-4">
                <div className="w-9 h-9 rounded-bc bg-bc-gray-100 flex items-center justify-center">
                  <CalendarClock className="w-5 h-5 text-bc-gray-500" />
                </div>
                <h2 className="text-lg font-semibold text-bc-gray-800">
                  {tf('Scheduled Plans (%d)', upcomingPlans.length)}
                </h2>
              </div>

              {upcomingPlans.map(plan => {
                const isRunning = activeJobs.some(job => job.plan_id === plan.plan_id)
                return (
                  <div
                    key={plan.plan_id}
                    className={`flex items-center gap-4 p-3 rounded-bc mb-2 last:mb-0 ${
                      isRunning
                        ? 'opacity-100 border border-bc-primary/30 bg-bc-primary-light/30'
                        : 'opacity-60 bg-bc-gray-50'
                    }`}
                  >
                    <div className={isRunning ? 'text-bc-primary' : 'text-bc-gray-400'}>
                      <CalendarClock className="w-5 h-5" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <p className="font-medium text-sm text-bc-gray-700 truncate">{plan.plan_name}</p>
                        {isRunning && (
                          <span className="text-xs bg-teal-100 text-teal-700 px-2 py-0.5 rounded shrink-0">
                            {t('Running now')}
                          </span>
                        )}
                      </div>
                      <p className="text-xs text-bc-gray-400">
                        {plan.schedule_text} · {tf('%d articles per run', plan.article_count)}
                      </p>
                    </div>
                    <div className="text-end shrink-0">
                      <p className="text-xs text-bc-gray-400">
                        {t('Next run')}:
                      </p>
                      <p className="text-sm font-medium text-bc-gray-500">
                        {formatNextRun(plan.next_run_at)}
                      </p>
                    </div>
                    <Button variant="ghost" size="sm" onClick={() => navigate('/plans')}>
                      {t('View plan')}
                    </Button>
                  </div>
                )
              })}
            </CardContent>
          </Card>
        )}

        {/* Active Jobs */}
        <Card padding="none">
          <CardContent className="p-6">
            <div className="flex items-center gap-3 mb-4">
              <div className="w-9 h-9 rounded-bc bg-bc-primary-light flex items-center justify-center">
                <Activity className="w-5 h-5 text-bc-primary" />
              </div>
              <div>
                <h2 className="text-lg font-semibold text-bc-gray-800">
                  {tf('Active Jobs (%d)', activeJobs.length)}
                </h2>
              </div>
              {activeJobs.length > 0 && (
                <div className="ms-auto flex items-center gap-1 text-xs text-bc-gray-400">
                  <span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
                  {t('Live')}
                </div>
              )}
            </div>

            {activeJobs.length === 0 ? (
              <div className="text-center py-8">
                <CheckCircle className="w-10 h-10 text-bc-gray-300 mx-auto mb-3" />
                <p className="text-bc-gray-400">{t('No active jobs')}</p>
                <p className="text-xs text-bc-gray-300 mt-1">
                  {t('Jobs will appear here when you start generating content')}
                </p>
              </div>
            ) : (
              activeJobs.map(job => (
                <ActiveJobCard key={job.id} job={job} onView={handleView} />
              ))
            )}
          </CardContent>
        </Card>

        {/* Job History */}
        <Card padding="none">
          <CardContent className="p-6">
            <div className="flex items-center gap-3 mb-4">
              <div className="w-9 h-9 rounded-bc bg-bc-gray-100 flex items-center justify-center">
                <Clock className="w-5 h-5 text-bc-gray-600" />
              </div>
              <h2 className="text-lg font-semibold text-bc-gray-800">{t('Job History')}</h2>
            </div>

            <div className="flex gap-2 mb-4">
              {(['all', 'complete', 'failed'] as FilterStatus[]).map(f => (
                <button
                  key={f}
                  type="button"
                  onClick={() => handleFilterChange(f)}
                  className={`px-3 py-1.5 text-sm rounded-bc transition-colors cursor-pointer border-none ${
                    filter === f
                      ? 'bg-bc-primary text-white font-medium'
                      : 'bg-bc-gray-100 text-bc-gray-600 hover:bg-bc-gray-200'
                  }`}
                >
                  {f === 'all' ? t('All') : f === 'complete' ? t('Completed') : t('Failed')}
                </button>
              ))}
            </div>

            {historyJobs.length === 0 ? (
              <div className="text-center py-8">
                <AlertCircle className="w-10 h-10 text-bc-gray-300 mx-auto mb-3" />
                <p className="text-bc-gray-400">
                  {filter === 'all' ? t('No job history yet') : t('No jobs matching this filter')}
                </p>
              </div>
            ) : (
              <>
                {historyJobs.map(job => (
                  <HistoryJobCard
                    key={job.id}
                    job={job}
                    onView={handleView}
                    onRunAgain={handleRunAgain}
                  />
                ))}
                {canLoadMore && (
                  <button
                    type="button"
                    onClick={loadMore}
                    className="w-full py-3 text-sm text-bc-gray-500 hover:text-bc-gray-700 bg-transparent border border-bc-gray-200 rounded-bc mt-3 cursor-pointer flex items-center justify-center gap-2"
                  >
                    <ArrowRight className="w-4 h-4" />
                    {t('Load more')}
                  </button>
                )}
              </>
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  )
}
