'use client';

import { useState, useEffect, useCallback, useRef } from 'react';
import type { 
  UseTranslationSubmitReturn, 
  TranslationConfig, 
  TranslationStatus,
  TranslationSubmitResponse,
  TranslationStatusResponse 
} from './types';
import { API_BASE } from '@/lib/config';
const POLLING_INTERVAL_MS = 2000;
const MAX_POLLING_FAILURES = 3;

/* ── Job persistence: survive a refresh mid-translation ─────────── */
const ACTIVE_JOB_KEY = 'wordly:activeJob';
const RECENT_JOBS_KEY = 'wordly:recentJobs';
const MAX_RECENT_JOBS = 20;
const ACTIVE_JOB_TTL_MS = 24 * 60 * 60 * 1000; // discard stale entries after 24h

interface StoredJob { jobId: string; fileName: string | null; savedAt: number }

export interface RecentJob { jobId: string; fileName: string; completedAt: number }

/** Server history (last completed jobs, newest first) — empty when offline/unauthenticated. */
export async function fetchServerHistory(perPage = 6): Promise<RecentJob[]> {
  if (typeof window === 'undefined') return [];
  const token = localStorage.getItem('token');
  if (!token) return [];
  try {
    const res = await fetch(`${API_BASE}/api/v1/translations?per_page=${perPage}`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!res.ok) return [];
    const json = await res.json();
    return (json.data ?? [])
      .filter((j: { status?: string | null }) => (j.status ?? 'completed') === 'completed')
      .map((j: {
        id: string; file_name?: string | null; status?: string | null;
        completed_at?: string | null; created_at?: string | null;
      }) => ({
        jobId: j.id,
        fileName: j.file_name ?? '',
        completedAt: Date.parse(j.completed_at ?? j.created_at ?? '') || Date.now(),
      }));
  } catch {
    return [];
  }
}

export function getRecentJobs(): RecentJob[] {
  if (typeof window === 'undefined') return [];
  try {
    const list = JSON.parse(localStorage.getItem(RECENT_JOBS_KEY) ?? '[]');
    return Array.isArray(list) ? list : [];
  } catch {
    return [];
  }
}

/** Remove a job from this browser's local history. */
export function removeRecentJob(jobId: string) {
  try {
    const list = getRecentJobs().filter(j => j.jobId !== jobId);
    localStorage.setItem(RECENT_JOBS_KEY, JSON.stringify(list));
  } catch { /* ignore */ }
}

/**
 * Delete a job on the server (history entry + review segments).
 * Silent by design: a 404 means the server already forgot the job, which
 * is exactly the state the caller wants.
 */
export async function deleteServerJob(jobId: string): Promise<void> {
  if (typeof window === 'undefined') return;
  const token = localStorage.getItem('token');
  if (!token) return;
  try {
    await fetch(`${API_BASE}/api/v1/translations/${jobId}`, {
      method: 'DELETE',
      headers: { Authorization: `Bearer ${token}` },
    });
  } catch { /* offline — the local entry is removed regardless */ }
}

function persistActiveJob(job: StoredJob | null) {
  try {
    if (!job) localStorage.removeItem(ACTIVE_JOB_KEY);
    else localStorage.setItem(ACTIVE_JOB_KEY, JSON.stringify(job));
  } catch { /* storage unavailable — session-only fallback */ }
}

export function pushRecentJob(job: RecentJob) {
  try {
    const list = getRecentJobs().filter(j => j.jobId !== job.jobId);
    list.unshift(job);
    localStorage.setItem(RECENT_JOBS_KEY, JSON.stringify(list.slice(0, MAX_RECENT_JOBS)));
  } catch { /* ignore */ }
}

export function useTranslationSubmit(): UseTranslationSubmitReturn {
  const [jobId, setJobId] = useState<string | null>(null);
  const [status, setStatus] = useState<TranslationStatus>('idle');
  const [progress, setProgress] = useState(0);
  const [currentStep, setCurrentStep] = useState('');
  const [error, setError] = useState<string | null>(null);
  const [estimatedRemaining, setEstimatedRemaining] = useState<number | null>(null);
  const [fileName, setFileName] = useState<string | null>(null);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [pollingFailures, setPollingFailures] = useState(0);
  const [isPolling, setIsPolling] = useState(false);
  
  const pollingIntervalRef = useRef<NodeJS.Timeout | null>(null);
  const isPollingRef = useRef(false);
  // Use a ref for failure count to avoid stale closure in the interval callback.
  // If we relied on state, the setInterval callback would always read the initial
  // value of pollingFailures (0) and never reach MAX_POLLING_FAILURES.
  const pollingFailuresRef = useRef(0);
  const resumeAttemptedRef = useRef(false);

  const stopPolling = useCallback(() => {
    if (pollingIntervalRef.current) {
      clearInterval(pollingIntervalRef.current);
      pollingIntervalRef.current = null;
    }
    isPollingRef.current = false;
    setIsPolling(false);
  }, []);

  const pollProgress = useCallback(async (id: string) => {
    if (isPollingRef.current) return;
    
    isPollingRef.current = true;
    
    try {
      const token = localStorage.getItem('token');
      const headers: Record<string, string> = {};
      if (token) {
        headers['Authorization'] = `Bearer ${token}`;
      }

      const response = await fetch(`${API_BASE}/api/v1/translations/${id}`, { headers });
      
      if (!response.ok) {
        if (response.status === 404) {
          stopPolling();
          setIsSubmitting(false);
          setStatus('failed');
          setError('Translation job not found');
          return;
        }
        // 429 (rate-limited) is not a real failure — just skip this poll
        if (response.status === 429) {
          return;
        }
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data: TranslationStatusResponse = await response.json();
      const job = data.data;

      setStatus(job.status as TranslationStatus);
      setProgress(job.progress_percent || 0);
      setCurrentStep(job.current_step || '');
      setEstimatedRemaining(data.meta.estimated_remaining_seconds ?? null);
      pollingFailuresRef.current = 0;
      setPollingFailures(0);
      
      if (job.file_name) {
        setFileName(job.file_name);
      }

      if (job.status === 'completed' || job.status === 'failed') {
        stopPolling();
        setIsSubmitting(false);
        if (job.status === 'failed') {
          setError(job.error_message || 'Translation failed');
        }
        if (job.status === 'completed') {
          pushRecentJob({ jobId: id, fileName: job.file_name || '', completedAt: Date.now() });
        }
      }
    } catch (err) {
      console.error('Polling error:', err);
      pollingFailuresRef.current += 1;
      setPollingFailures(pollingFailuresRef.current);
      
      if (pollingFailuresRef.current >= MAX_POLLING_FAILURES) {
        stopPolling();
        setIsSubmitting(false);
        setStatus('failed');
        setError('Lost connection to translation service. Please check your internet connection and try again.');
      }
    } finally {
      isPollingRef.current = false;
    }
  }, [stopPolling]);

  const startPolling = useCallback((id: string) => {
    stopPolling();
    pollingFailuresRef.current = 0;
    setIsPolling(true);
    setPollingFailures(0);
    
    pollProgress(id);
    
    pollingIntervalRef.current = setInterval(() => {
      pollProgress(id);
    }, POLLING_INTERVAL_MS);
  }, [pollProgress, stopPolling]);

  const submitTranslation = useCallback(async (file: File, config: TranslationConfig) => {
    setIsSubmitting(true);
    setError(null);
    setProgress(0);
    setCurrentStep('Uploading file...');
    setEstimatedRemaining(null);
    setStatus('processing'); // IMPORTANT: Set to 'processing' IMMEDIATELY so progress bar shows
    setFileName(file.name);
    setJobId(null);

    try {
      const formData = new FormData();
      formData.append('file', file);
      formData.append('source_lang', config.sourceLang);
      formData.append('target_lang', config.targetLang);
      formData.append('mode', config.mode);
      // Provider is configured server-side by admin — only send the provider name.
      if (config.mode === 'llm' && config.provider) {
        formData.append('provider', config.provider);
      }
      // PDF mode: layout (preserve layout) or text_only (clean text output)
      if (config.pdfMode) {
        formData.append('pdf_mode', config.pdfMode);
      }
      // Glossary for LLM translation (Pro only)
      if (config.glossaryId) {
        formData.append('glossary_id', config.glossaryId);
      }
      // Translate images toggle
      if (config.translateImages !== undefined) {
        formData.append('translate_images', String(config.translateImages));
      }
      // System prompt from Context page (Pro only)
      const { settings } = await import('@/lib/store').then(m => m.useTranslationStore.getState());
      if (settings.systemPrompt?.trim()) {
        formData.append('custom_prompt', settings.systemPrompt.trim());
      }

      const token = localStorage.getItem('token');
      const headers: Record<string, string> = {};
      if (token) {
        headers['Authorization'] = `Bearer ${token}`;
      }

      const response = await fetch(`${API_BASE}/api/v1/translate`, {
        method: 'POST',
        headers,
        body: formData,
      });

      if (!response.ok) {
        let errorMessage = `Translation failed: ${response.status}`;
        try {
          const errorData = await response.json();
          errorMessage = errorData.message || errorData.error || errorMessage;
        } catch {
          // Response not JSON, use default message
        }
        throw new Error(errorMessage);
      }

      const data: TranslationSubmitResponse = await response.json();
      
      setJobId(data.data.id);
      setFileName(data.data.file_name || file.name);
      setProgress(data.data.progress_percent || 5); // Start with at least 5%
      setCurrentStep(data.data.current_step || 'Translating...');
      
      startPolling(data.data.id);
    } catch (err) {
      setStatus('failed');
      setError(err instanceof Error ? err.message : 'Translation failed');
      setIsSubmitting(false);
    }
    // NOTE: Don't set isSubmitting(false) here - let polling handle the transition
  }, [startPolling]);

  /** Ask the backend to cancel the current job. Returns true on success. */
  const cancelJob = useCallback(async (): Promise<boolean> => {
    const id = jobId;
    if (!id) return false;
    try {
      const token = localStorage.getItem('token');
      const headers: Record<string, string> = {};
      if (token) headers['Authorization'] = `Bearer ${token}`;
      const res = await fetch(`${API_BASE}/api/v1/translations/${id}/cancel`, {
        method: 'POST',
        headers,
      });
      if (!res.ok) return false;
      stopPolling();
      persistActiveJob(null);
      setIsSubmitting(false);
      return true;
    } catch {
      return false;
    }
  }, [jobId, stopPolling]);

  const reset = useCallback(() => {
    stopPolling();
    persistActiveJob(null);
    setJobId(null);
    setStatus('idle');
    setProgress(0);
    setCurrentStep('');
    setError(null);
    setEstimatedRemaining(null);
    setFileName(null);
    setIsSubmitting(false);
    setPollingFailures(0);
  }, [stopPolling]);

  // Persist the active job whenever it changes so a refresh can resume polling.
  useEffect(() => {
    if (jobId) persistActiveJob({ jobId, fileName, savedAt: Date.now() });
  }, [jobId, fileName]);

  // Resume an interrupted job once on mount (page refreshed mid-translation).
  useEffect(() => {
    if (resumeAttemptedRef.current) return;
    resumeAttemptedRef.current = true;
    try {
      const raw = localStorage.getItem(ACTIVE_JOB_KEY);
      if (!raw) return;
      const stored: StoredJob = JSON.parse(raw);
      if (!stored?.jobId || Date.now() - stored.savedAt > ACTIVE_JOB_TTL_MS) {
        persistActiveJob(null);
        return;
      }
      setJobId(stored.jobId);
      if (stored.fileName) setFileName(stored.fileName);
      setStatus('processing');
      setProgress(0);
      startPolling(stored.jobId);
    } catch {
      persistActiveJob(null);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    return () => {
      stopPolling();
    };
  }, [stopPolling]);

  return {
    submitTranslation,
    cancelJob,
    jobId,
    status,
    progress,
    currentStep,
    error,
    estimatedRemaining,
    fileName,
    reset,
    isSubmitting,
    isPolling,
    pollingFailures,
  };
}
