/**
 * Editor page — GLSL editor with live WebGL preview.
 *
 * Features:
 * - Resizable split pane with drag handle
 * - Save as draft or publish
 * - Version history (when editing existing shader)
 * - Live preview with 400ms debounce
 */

import { useState, useEffect, useCallback, useRef } from 'react';
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import api from '@/lib/api';
import { useAuthStore } from '@/stores/auth';
import ShaderCanvas from '@/components/ShaderCanvas';

const DEFAULT_SHADER = `// Fractafrag — write your shader here
// Shadertoy-compatible: mainImage(out vec4 fragColor, in vec2 fragCoord)
// Available uniforms: iTime, iResolution, iMouse

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    float t = iTime;

    // Gradient with time-based animation
    vec3 col = 0.5 + 0.5 * cos(t + uv.xyx + vec3(0, 2, 4));

    // Add some structure
    float d = length(uv - 0.5);
    col *= 1.0 - smoothstep(0.0, 0.5, d);
    col += 0.05;

    fragColor = vec4(col, 1.0);
}
`;

export default function Editor() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const { isAuthenticated, user } = useAuthStore();

  // Fulfillment context — read once from URL, persist in ref so it survives navigation
  const fulfillId = searchParams.get('fulfill');
  const fulfillDesireId = useRef(fulfillId);

  const [code, setCode] = useState(DEFAULT_SHADER);
  const [liveCode, setLiveCode] = useState(DEFAULT_SHADER);
  const [title, setTitle] = useState('Untitled Shader');
  const [description, setDescription] = useState('');
  const [tags, setTags] = useState('');
  const [shaderType, setShaderType] = useState('2d');
  const [compileError, setCompileError] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState('');
  const [showMeta, setShowMeta] = useState(false);
  const [savedStatus, setSavedStatus] = useState<string | null>(null);
  const [editingExisting, setEditingExisting] = useState(false);

  // Resizable pane state
  const [editorWidth, setEditorWidth] = useState(50); // percentage
  const isDragging = useRef(false);
  const containerRef = useRef<HTMLDivElement>(null);

  const debounceRef = useRef<ReturnType<typeof setTimeout>>();

  // Load existing shader for editing or forking
  const { data: existingShader } = useQuery({
    queryKey: ['shader', id],
    queryFn: async () => {
      const { data } = await api.get(`/shaders/${id}`);
      return data;
    },
    enabled: !!id,
  });

  // Fetch desire context when fulfilling
  const { data: fulfillDesire } = useQuery({
    queryKey: ['desire', fulfillDesireId.current],
    queryFn: async () => {
      const { data } = await api.get(`/desires/${fulfillDesireId.current}`);
      return data;
    },
    enabled: !!fulfillDesireId.current,
  });

  useEffect(() => {
    if (existingShader) {
      setCode(existingShader.glsl_code);
      setLiveCode(existingShader.glsl_code);
      setTitle(existingShader.title);
      setDescription(existingShader.description || '');
      setShaderType(existingShader.shader_type);
      setTags(existingShader.tags?.join(', ') || '');

      // If we own it, we're editing; otherwise forking
      if (user && existingShader.author_id === user.id) {
        setEditingExisting(true);
      } else {
        setTitle(`Fork of ${existingShader.title}`);
        setEditingExisting(false);
      }
    }
  }, [existingShader, user]);

  // ── Drag handle for resizable pane ──────────────────────
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    e.preventDefault();
    isDragging.current = true;
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';
  }, []);

  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      if (!isDragging.current || !containerRef.current) return;
      const rect = containerRef.current.getBoundingClientRect();
      const pct = ((e.clientX - rect.left) / rect.width) * 100;
      setEditorWidth(Math.max(20, Math.min(80, pct)));
    };
    const handleMouseUp = () => {
      isDragging.current = false;
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };
    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
    return () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };
  }, []);

  // ── Debounced live preview ──────────────────────────────
  const handleCodeChange = useCallback((value: string) => {
    setCode(value);
    setSavedStatus(null);
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      setLiveCode(value);
    }, 400);
  }, []);

  // ── Save / Publish ─────────────────────────────────────
  const handleSave = async (publishStatus: 'draft' | 'published') => {
    if (!isAuthenticated()) {
      navigate('/login');
      return;
    }

    setSubmitting(true);
    setSubmitError('');

    const payload = {
      title,
      description,
      glsl_code: code,
      tags: tags.split(',').map(t => t.trim()).filter(Boolean),
      shader_type: shaderType,
      status: publishStatus,
      is_public: publishStatus === 'published',
    };

    try {
      if (editingExisting && id) {
        // Update existing shader
        const { data } = await api.put(`/shaders/${id}`, {
          ...payload,
          change_note: publishStatus === 'published' ? 'Updated' : undefined,
        });
        setSavedStatus(publishStatus === 'draft' ? 'Draft saved' : 'Published');
        if (publishStatus === 'published') {
          setTimeout(() => navigate(`/shader/${data.id}`), 800);
        }
      } else {
        // Create new shader
        const { data } = await api.post('/shaders', {
          ...payload,
          fulfills_desire_id: fulfillDesireId.current || undefined,
        });
        if (publishStatus === 'published') {
          navigate(`/shader/${data.id}`);
        } else {
          // Redirect to editor with the new ID so subsequent saves are updates
          setSavedStatus('Draft saved');
          navigate(`/editor/${data.id}`, { replace: true });
        }
      }
    } catch (err: any) {
      const detail = err.response?.data?.detail;
      if (typeof detail === 'object' && detail.errors) {
        setSubmitError(detail.errors.join('\n'));
      } else {
        setSubmitError(detail || 'Save failed');
      }
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <div className="h-[calc(100vh-3.5rem)] flex flex-col">
      {/* Toolbar */}
      <div className="flex items-center justify-between px-4 py-2 bg-surface-1 border-b border-surface-3">
        <div className="flex items-center gap-3">
          <input
            type="text"
            value={title}
            onChange={(e) => setTitle(e.target.value)}
            className="bg-transparent text-lg font-medium text-gray-100 focus:outline-none
                       border-b border-transparent focus:border-fracta-500 transition-colors w-64"
            placeholder="Shader title..."
          />
          <button
            onClick={() => setShowMeta(!showMeta)}
            className="btn-ghost text-xs py-1 px-2"
          >
            {showMeta ? 'Hide details' : 'Details'}
          </button>
          {editingExisting && existingShader && (
            <span className="text-xs text-gray-500">
              v{existingShader.current_version}
            </span>
          )}
        </div>

        <div className="flex items-center gap-2">
          {compileError && (
            <span className="text-xs text-red-400 max-w-xs truncate" title={compileError}>
              ⚠ {compileError.split('\n')[0]}
            </span>
          )}
          {savedStatus && (
            <span className="text-xs text-green-400 animate-fade-in">{savedStatus}</span>
          )}
          <button
            onClick={() => handleSave('draft')}
            disabled={submitting}
            className="btn-secondary text-sm py-1.5"
          >
            {submitting ? '...' : 'Save Draft'}
          </button>
          <button
            onClick={() => handleSave('published')}
            disabled={submitting || !!compileError}
            className="btn-primary text-sm py-1.5"
          >
            {submitting ? 'Publishing...' : 'Publish'}
          </button>
        </div>
      </div>

      {/* Metadata panel */}
      {showMeta && (
        <div className="px-4 py-3 bg-surface-1 border-b border-surface-3 flex gap-4 items-end animate-slide-up">
          <div className="flex-1">
            <label className="text-xs text-gray-500">Description</label>
            <input
              type="text"
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              className="input text-sm mt-1"
              placeholder="What does this shader do?"
            />
          </div>
          <div className="w-48">
            <label className="text-xs text-gray-500">Tags (comma-separated)</label>
            <input
              type="text"
              value={tags}
              onChange={(e) => setTags(e.target.value)}
              className="input text-sm mt-1"
              placeholder="fractal, noise, 3d"
            />
          </div>
          <div className="w-32">
            <label className="text-xs text-gray-500">Type</label>
            <select
              value={shaderType}
              onChange={(e) => setShaderType(e.target.value)}
              className="input text-sm mt-1"
            >
              <option value="2d">2D</option>
              <option value="3d">3D</option>
              <option value="audio-reactive">Audio</option>
            </select>
          </div>
        </div>
      )}

      {/* Submit error */}
      {submitError && (
        <div className="px-4 py-2 bg-red-600/10 text-red-400 text-sm border-b border-red-600/20">
          {submitError}
        </div>
      )}

      {/* Desire fulfillment context banner */}
      {fulfillDesire && (
        <div className="px-4 py-3 bg-amber-600/10 border-b border-amber-600/20 flex items-center gap-3">
          <span className="text-amber-400 text-sm font-medium">🎯 Fulfilling desire:</span>
          <span className="text-gray-300 text-sm flex-1">{fulfillDesire.prompt_text}</span>
          {fulfillDesire.style_hints && (
            <span className="text-xs text-gray-500">Style hints available</span>
          )}
        </div>
      )}

      {/* Split pane: editor + drag handle + preview */}
      <div ref={containerRef} className="flex-1 flex min-h-0">
        {/* Code editor */}
        <div className="flex flex-col" style={{ width: `${editorWidth}%` }}>
          <div className="px-3 py-1.5 bg-surface-2 text-xs text-gray-500 border-b border-surface-3 flex items-center gap-2">
            <span className="w-2 h-2 rounded-full bg-green-500" />
            fragment.glsl
          </div>
          <textarea
            value={code}
            onChange={(e) => handleCodeChange(e.target.value)}
            className="flex-1 bg-surface-0 text-gray-200 font-mono text-sm p-4
                       resize-none focus:outline-none leading-relaxed
                       selection:bg-fracta-600/30"
            spellCheck={false}
            autoCapitalize="off"
            autoCorrect="off"
          />
        </div>

        {/* Drag handle */}
        <div
          onMouseDown={handleMouseDown}
          className="w-1.5 bg-surface-3 hover:bg-fracta-600 cursor-col-resize
                     transition-colors flex-shrink-0 relative group"
        >
          <div className="absolute inset-y-0 -left-1 -right-1" /> {/* Wider hit area */}
          <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2
                          w-1 h-8 bg-gray-600 group-hover:bg-fracta-400 rounded-full transition-colors" />
        </div>

        {/* Live preview */}
        <div className="flex-1 bg-black relative min-w-0">
          <ShaderCanvas
            code={liveCode}
            className="w-full h-full"
            animate={true}
            onError={(err) => setCompileError(err)}
            onCompileSuccess={() => setCompileError('')}
          />
          {!liveCode.trim() && (
            <div className="absolute inset-0 flex items-center justify-center text-gray-600">
              Write some GLSL to see it rendered live
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
