import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Download, ExternalLink, ImagePlus, Loader2, Sparkles, UploadCloud } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  checkDreamWeaverHealth,
  fetchDreamWeaverResult,
  getDreamWeaverStatus,
  submitDreamWeaverJob,
  type DreamWeaverHealth,
  type DreamWeaverJobResponse,
} from '@/shared/lib/dreamWeaverApi';
import styles from './ReimaginePanel.module.css';

type RoomType = 'bedroom' | 'living_room' | 'bathroom' | 'kitchen' | 'dining_room' | 'office';
type Phase = 'idle' | 'ready' | 'generating' | 'result' | 'error';

interface ReimagineResult {
  url: string;
  jobId: string;
  blob: Blob;
}

interface ReimaginePanelProps {
  propertyId: string;
  roomImageUrl?: string;
  onResultSaved?: (url: string) => void;
}

const ROOM_TYPES: { id: RoomType; label: string }[] = [
  { id: 'bedroom', label: 'Bedroom' },
  { id: 'living_room', label: 'Living Room' },
  { id: 'bathroom', label: 'Bathroom' },
  { id: 'kitchen', label: 'Kitchen' },
  { id: 'dining_room', label: 'Dining Room' },
  { id: 'office', label: 'Office' },
];

const DEFAULT_PROMPT = 'Modern luxury staging, warm practical lighting, premium materials, uncluttered real estate brochure finish';

export function ReimaginePanel({ propertyId, roomImageUrl, onResultSaved }: ReimaginePanelProps) {
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [phase, setPhase] = useState<Phase>('idle');
  const [health, setHealth] = useState<DreamWeaverHealth | null>(null);
  const [roomType, setRoomType] = useState<RoomType>('bedroom');
  const [keywords, setKeywords] = useState(DEFAULT_PROMPT);
  const [sourceFile, setSourceFile] = useState<File | null>(null);
  const [sourcePreview, setSourcePreview] = useState<string | null>(roomImageUrl ?? null);
  const [job, setJob] = useState<DreamWeaverJobResponse | null>(null);
  const [result, setResult] = useState<ReimagineResult | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [pollCount, setPollCount] = useState(0);

  useEffect(() => {
    let alive = true;
    checkDreamWeaverHealth()
      .then((value) => {
        if (!alive) return;
        setHealth(value);
        setPhase('ready');
      })
      .catch((err) => {
        if (!alive) return;
        setError(err instanceof Error ? err.message : 'Dream Weaver health check failed.');
        setPhase('error');
      });
    return () => { alive = false; };
  }, []);

  useEffect(() => {
    return () => {
      if (sourcePreview?.startsWith('blob:')) URL.revokeObjectURL(sourcePreview);
      if (result?.url.startsWith('blob:')) URL.revokeObjectURL(result.url);
    };
  }, [sourcePreview, result]);

  const canGenerate = Boolean(sourceFile) && phase !== 'generating';
  const healthLabel = useMemo(() => {
    if (!health) return 'Checking Dream Weaver';
    if (health.online && health.routeMounted) return 'Dream Weaver online';
    return health.detail || health.status || 'Dream Weaver unavailable';
  }, [health]);

  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0] ?? null;
    if (!file) return;
    if (sourcePreview?.startsWith('blob:')) URL.revokeObjectURL(sourcePreview);
    setSourceFile(file);
    setSourcePreview(URL.createObjectURL(file));
    setResult(null);
    setError(null);
    setPhase('ready');
  };

  const handleGenerate = useCallback(async () => {
    if (!sourceFile) {
      setError('Upload a room image before generating.');
      setPhase('error');
      return;
    }
    setPhase('generating');
    setError(null);
    setPollCount(0);

    try {
      const submitted = await submitDreamWeaverJob({ image: sourceFile, roomType, keywords });
      setJob(submitted);

      for (let attempt = 1; attempt <= 180; attempt += 1) {
        setPollCount(attempt);
        const status = await getDreamWeaverStatus(submitted);
        if (status.status === 'failed') {
          throw new Error(status.error || 'Dream Weaver generation failed.');
        }
        if (status.ready || status.status === 'complete') {
          const blob = await fetchDreamWeaverResult(submitted.job_id, status.result_url ?? submitted.result_url);
          const url = URL.createObjectURL(blob);
          setResult({ url, jobId: submitted.job_id, blob });
          setPhase('result');
          return;
        }
        await new Promise((resolve) => window.setTimeout(resolve, 2000));
      }
      throw new Error('Dream Weaver timed out before returning an image.');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Dream Weaver request failed.');
      setPhase('error');
    }
  }, [keywords, roomType, sourceFile]);

  const handleDownload = () => {
    if (!result) return;
    const anchor = document.createElement('a');
    anchor.href = result.url;
    anchor.download = `${propertyId}-reimagine-${result.jobId}.png`;
    anchor.click();
  };

  return (
    <div className={styles.root}>
      <section className={styles.sourcePanel}>
        <div className={styles.panelHeader}>
          <div>
            <span className={styles.eyebrow}>Source Room</span>
            <h3>Reimagine this space</h3>
          </div>
          <span className={health?.online ? styles.healthOk : styles.healthWarn}>{healthLabel}</span>
        </div>

        <button className={styles.uploadFrame} onClick={() => fileInputRef.current?.click()} type="button">
          {sourcePreview ? <img src={sourcePreview} alt="Selected room" /> : (
            <span className={styles.uploadEmpty}>
              <UploadCloud size={28} />
              Upload room image
            </span>
          )}
        </button>
        <input ref={fileInputRef} className={styles.fileInput} type="file" accept="image/*" onChange={handleFileChange} />

        <div className={styles.roomGrid}>
          {ROOM_TYPES.map((room) => (
            <button
              key={room.id}
              type="button"
              className={roomType === room.id ? styles.roomActive : styles.roomButton}
              onClick={() => setRoomType(room.id)}
            >
              {room.label}
            </button>
          ))}
        </div>

        <label className={styles.promptLabel}>
          Styling prompt
          <textarea value={keywords} onChange={(event) => setKeywords(event.target.value)} />
        </label>

        <button className={styles.generateButton} onClick={() => void handleGenerate()} disabled={!canGenerate}>
          {phase === 'generating' ? <Loader2 size={18} className={styles.spin} /> : <Sparkles size={18} />}
          Generate
        </button>
      </section>

      <section className={styles.resultPanel}>
        <AnimatePresence mode="wait">
          {phase === 'generating' && (
            <motion.div key="generating" className={styles.resultState} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
              <Loader2 className={styles.spin} size={34} />
              <strong>Reimagining your space</strong>
              <span>Render processing - poll {pollCount}/180</span>
            </motion.div>
          )}

          {phase === 'result' && result && (
            <motion.div key="result" className={styles.resultReady} initial={{ opacity: 0, scale: 0.98 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0 }}>
              <img src={result.url} alt="Generated staging" />
              <div className={styles.resultActions}>
                <button className="btn-primary" onClick={() => onResultSaved?.(result.url)}>
                  <ImagePlus size={16} /> Use This
                </button>
                <button className="btn-ghost" onClick={handleDownload}>
                  <Download size={16} /> Download
                </button>
                <button className="btn-ghost" onClick={() => window.open(result.url, '_blank', 'noopener,noreferrer')}>
                  <ExternalLink size={16} /> Open
                </button>
              </div>
            </motion.div>
          )}

          {(phase === 'ready' || phase === 'idle') && (
            <motion.div key="empty" className={styles.resultState} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
              <Sparkles size={34} />
              <strong>No generated image yet</strong>
              <span>Upload an image, tune the prompt, and generate a staged render.</span>
            </motion.div>
          )}

          {phase === 'error' && (
            <motion.div key="error" className={styles.errorState} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
              <strong>Dream Weaver unavailable</strong>
              <span>{error}</span>
              <button className="btn-ghost" onClick={() => setPhase(sourceFile ? 'ready' : 'idle')}>Dismiss</button>
            </motion.div>
          )}
        </AnimatePresence>
      </section>
    </div>
  );
}
