import { useEffect, useRef, useState } from 'react'
import { APP_NAME } from '@/constants/app.constant'
import { getMigrateUrl, getSetupStatus } from '@/services/setup.service'
import { applicationConfigurationUrl } from '@/services/abpConfig.service'

interface LogLine {
  level: 'info' | 'warn' | 'error' | 'success' | 'restart' | 'done'
  message: string
}

type MigrationStatus = 'idle' | 'running' | 'success' | 'error' | 'restarting'

const levelClass: Record<string, string> = {
  info: 'text-gray-300',
  warn: 'text-yellow-400',
  error: 'text-red-400',
  success: 'text-green-400',
  restart: 'text-blue-400',
  done: 'text-blue-400',
}

/**
 * Sunucu yeniden başlayana kadar ABP config endpoint'ini poll eder.
 * Arka arkaya 2 başarılı yanıt alındığında onReady çağrılır.
 * @param onReady Sunucu hazır olduğunda çağrılacak callback
 * @param onAttempt Her denemede kaçıncı deneme olduğunu bildiren opsiyonel callback
 */
const pollUntilServerReady = (onReady: () => void, onAttempt?: (attempt: number) => void): (() => void) => {
  const REQUIRED_SUCCESS = 2
  let attempt = 0
  let successCount = 0
  let timerId: ReturnType<typeof setTimeout> | null = null
  let cancelled = false

  const tick = async () => {
    if (cancelled) return
    attempt++
    onAttempt?.(attempt)

    try {
      const res = await fetch(
        `${import.meta.env.VITE_API_URL ?? ''}${applicationConfigurationUrl(false)}`,
        { method: 'GET', headers: { Accept: 'application/json' }, cache: 'no-store' },
      )
      if (res.status === 200) {
        try {
          const json = await res.json()
          if (json && typeof json.currentUser === 'object') {
            successCount++
            if (successCount >= REQUIRED_SUCCESS) {
              onReady()
              return
            }
            timerId = setTimeout(tick, 1000)
            return
          }
        } catch { /* parse hatası */ }
      }
      successCount = 0
    } catch {
      successCount = 0
    }
    timerId = setTimeout(tick, 2000)
  }

  // İlk denemeden önce kısa bekleme (sunucunun kapanma süresi)
  timerId = setTimeout(tick, 3000)

  // İptal fonksiyonu döner
  return () => {
    cancelled = true
    if (timerId) clearTimeout(timerId)
  }
}

const DatabaseSetup = () => {
  const [logs, setLogs] = useState<LogLine[]>([])
  const [status, setStatus] = useState<MigrationStatus>('idle')
  const [pollCountdown, setPollCountdown] = useState(0)
  const [dbExists, setDbExists] = useState<boolean | null>(null)
  const logEndRef = useRef<HTMLDivElement>(null)
  const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Auto-scroll to bottom when new logs arrive
  useEffect(() => {
    logEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }, [logs])

  // Check DB existence on mount
  useEffect(() => {
    getSetupStatus()
      .then((res) => setDbExists(res.data.dbExists))
      .catch(() => setDbExists(false))
  }, [])

  // Cleanup on component unmount
  useEffect(() => {
    return () => {
      const ref = pollTimerRef.current as any
      if (ref?.unref) ref.unref()
      else if (pollTimerRef.current) clearTimeout(pollTimerRef.current as any)
    }
  }, [])

  const addLog = (level: LogLine['level'], message: string) => {
    setLogs((prev) => [...prev, { level, message }])
  }

  // ── Poll ABP config endpoint until server is ready ──────────────
  const pollUntilReady = () => {
    setStatus('restarting')
    const cancel = pollUntilServerReady(
      () => { window.location.href = '/' },
      (attempt) => setPollCountdown(attempt),
    )
    pollTimerRef.current = { unref: cancel } as any
  }

  const startMigration = async () => {
    if (status === 'running') return

    setLogs([])
    setStatus('running')
    addLog('info', 'Starting migration...')

    const url = getMigrateUrl()
    const abortController = new AbortController()

    const parseChunk = (chunk: string) => {
      // SSE format: "data: {...}\n\n"
      const lines = chunk.split('\n')
      for (const line of lines) {
        const trimmed = line.trim()
        if (!trimmed.startsWith('data:')) continue
        const raw = trimmed.slice(5).trim()
        if (!raw) continue
        try {
          const data = JSON.parse(raw) as { level?: string; message?: string }
          const level = (data.level ?? 'info') as LogLine['level']
          const message = data.message ?? raw

          if (level === 'done') {
            setStatus((prev) => {
              if (prev === 'running') return 'error'
              return prev
            })
            return
          }

          addLog(level, message)

          if (level === 'success') {
            setStatus('success')
          } else if (level === 'error') {
            setStatus('error')
          } else if (level === 'restart') {
            pollUntilReady()
          }
        } catch {
          addLog('info', raw)
        }
      }
    }

    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: { Accept: 'text/event-stream' },
        signal: abortController.signal,
      })

      if (!response.ok || !response.body) {
        addLog('error', `Server responded with status ${response.status}`)
        setStatus('error')
        return
      }

      const reader = response.body.getReader()
      const decoder = new TextDecoder()

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const { done, value } = await reader.read()
        if (done) break
        parseChunk(decoder.decode(value, { stream: true }))
      }
    } catch (err: any) {
      if (err?.name !== 'AbortError') {
        setStatus((prev) => (prev === 'running' ? 'error' : prev))
        addLog('error', 'Server connection lost or migration could not be completed.')
      }
    }
  }

  return (
    <div className="min-h-screen bg-gray-900 flex flex-col items-center justify-center p-6 text-white">
      {/* Header */}
      <div className="mb-8 text-center">
        <h1 className="text-3xl font-bold mb-2">{APP_NAME}</h1>
        <p className="text-gray-400 text-lg">Initial Setup — Creating Database</p>
      </div>

      {/* Status Card */}
      <div className="w-full max-w-4xl bg-gray-800 rounded-xl shadow-2xl overflow-hidden">
        {/* Card Header */}
        <div className="flex items-center justify-between px-5 py-4 bg-gray-700 border-b border-gray-600">
          <div className="flex items-center gap-3">
            <StatusIndicator status={status} />
            <span className="font-semibold text-sm tracking-wide">
              {status === 'idle' && 'Ready to Setup'}
              {status === 'running' && 'Migration Running...'}
              {status === 'success' && 'Migration Completed ✓'}
              {status === 'restarting' && `Server Restarting... (attempt ${pollCountdown})`}
              {status === 'error' && 'Migration Failed ✗'}
            </span>
          </div>
          <span className="text-xs text-gray-400">{logs.length} log lines</span>
        </div>

        {/* Log Terminal */}
        <div className="h-96 overflow-y-auto bg-gray-950 px-4 py-3 font-mono text-xs leading-relaxed">
          {logs.length === 0 ? (
            <p className="text-gray-600 mt-2">Logs will appear here when migration starts...</p>
          ) : (
            logs.map((line, i) => (
              <div key={i} className={`${levelClass[line.level] ?? 'text-gray-300'} mb-0.5`}>
                <span className="text-gray-600 mr-2 select-none">{String(i + 1).padStart(4, '0')}</span>
                {line.message}
              </div>
            ))
          )}
          <div ref={logEndRef} />
        </div>

        {/* Action Area */}
        <div className="flex items-center justify-between px-5 py-4 bg-gray-700 border-t border-gray-600">
          <div className="text-xs text-gray-400">
            {status === 'idle' && dbExists === true && 'Database already exists. Migration is not required.'}
            {status === 'idle' && dbExists === false && 'Database not found. Press the button to start migration.'}
            {status === 'idle' && dbExists === null && 'Checking database status...'}
            {status === 'running' && 'Please wait, migration is in progress...'}
            {status === 'success' && 'Migration completed. Server is restarting...'}
            {status === 'restarting' &&
              'Waiting for application server to be ready, you will be redirected automatically...'}
            {status === 'error' &&
              'Review the errors in the logs, fix the issue, and try again.'}
          </div>

          <div className="flex gap-3">
            {(status === 'idle' || status === 'error') && !dbExists && (
              <button
                onClick={startMigration}
                className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium rounded-lg transition-colors"
              >
                {status === 'error' ? 'Retry' : 'Start Setup'}
              </button>
            )}

            {status === 'restarting' && (
              <div className="flex items-center gap-2 text-blue-400 text-sm">
                <span className="inline-block w-3 h-3 rounded-full bg-blue-400 animate-ping" />
                Waiting...
              </div>
            )}
          </div>
        </div>
      </div>

      <p className="mt-6 text-xs text-gray-600">
        This page is only visible when the database does not exist.
      </p>
    </div>
  )
}

// ─── Status Indicator ────────────────────────────────────────────────────────

const StatusIndicator = ({ status }: { status: MigrationStatus }) => {
  const cls: Record<MigrationStatus, string> = {
    idle: 'bg-gray-500',
    running: 'bg-yellow-400 animate-pulse',
    success: 'bg-green-500',
    restarting: 'bg-blue-400 animate-ping',
    error: 'bg-red-500',
  }
  return <span className={`inline-block w-3 h-3 rounded-full ${cls[status]}`} />
}

export default DatabaseSetup


