import React, { useCallback, useRef, useState, useMemo, useEffect } from 'react';
import ReactFlow, {
  addEdge,
  useNodesState,
  useEdgesState,
  Controls,
  Background,
  Connection,
  Edge,
  Node,
  BackgroundVariant,
  Panel,
  ConnectionMode
} from 'reactflow';
import { FileText, CheckCircle, AlertTriangle, X, Copy, Check, Lightbulb, Key, Wrench, Menu, Activity } from 'lucide-react';
import Sidebar from './Sidebar';
import PropertiesPanel from './PropertiesPanel';
import CustomNode from './CustomNode';
import CodeViewer from './CodeViewer';
import AIBuilderModal from './AIBuilderModal';
import SuggestionsModal from './SuggestionsModal';
import ApiKeyModal from './ApiKeyModal';
import FixerModal from './FixerModal';
import { INITIAL_NODES, INITIAL_EDGES, LAYER_DEFINITIONS, TEMPLATES } from '../constants';
import { generateRefinedPrompt, validateArchitecture, getArchitectureSuggestions, getUserApiKey, implementArchitectureSuggestions } from '../services/geminiService';
import { NodeData, LayerType, LogEntry } from '../types';

let id = 1000;
const getId = () => `${id++}`;

// --- MAIN BUILDER CONTENT ---
interface BuilderProps {
  onBackToHome: () => void;
}

const Builder: React.FC<BuilderProps> = ({ onBackToHome }) => {
  const reactFlowWrapper = useRef<HTMLDivElement>(null);
  const [nodes, setNodes, onNodesChange] = useNodesState(INITIAL_NODES);
  const [edges, setEdges, onEdgesChange] = useEdgesState(INITIAL_EDGES);
  const [reactFlowInstance, setReactFlowInstance] = useState<any>(null);
  const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
  
  const [generatedPrompt, setGeneratedPrompt] = useState('');
  const [isPromptViewerOpen, setIsPromptViewerOpen] = useState(false);
  const [isGeneratingPrompt, setIsGeneratingPrompt] = useState(false);
  
  const [validationMsg, setValidationMsg] = useState<string | null>(null);
  const [layoutCopied, setLayoutCopied] = useState(false);

  // Responsive Layout State
  const [isSidebarOpen, setIsSidebarOpen] = useState(true);
  const [isPropertiesOpen, setIsPropertiesOpen] = useState(false);

  // Suggestions State
  const [isSuggestionsOpen, setIsSuggestionsOpen] = useState(false);
  const [suggestionsText, setSuggestionsText] = useState('');
  const [isSuggestionsLoading, setIsSuggestionsLoading] = useState(false);
  const [isImplementingSuggestions, setIsImplementingSuggestions] = useState(false);

  // Fixer State
  const [isFixerOpen, setIsFixerOpen] = useState(false);

  // AI Builder and Template State
  const [isAIBuilderOpen, setIsAIBuilderOpen] = useState(false);
  const [isTemplateMenuOpen, setIsTemplateMenuOpen] = useState(false);

  // API Key State
  const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false);
  const [isConnected, setIsConnected] = useState(false);

  // Activity Log State
  const [logs, setLogs] = useState<LogEntry[]>([]);

  const addLog = useCallback((message: string, type: 'info' | 'success' | 'warning' | 'error' = 'info') => {
    setLogs(prev => [{
      id: Date.now().toString() + Math.random(),
      timestamp: new Date(),
      message,
      type
    }, ...prev]);
  }, []);

  // Initialize responsiveness
  useEffect(() => {
    const handleResize = () => {
      if (window.innerWidth < 768) {
        setIsSidebarOpen(false);
      } else {
        setIsSidebarOpen(true);
      }
    };
    
    // Set initial state
    handleResize();
    
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  // Load connection status on mount
  useEffect(() => {
    setIsConnected(!!getUserApiKey());
    addLog('System initialized. Ready to build.', 'info');
  }, [addLog]);

  // Define custom node types
  const nodeTypes = useMemo(() => ({ custom: CustomNode }), []);

  const onConnect = useCallback(
    (params: Connection) => setEdges((eds) => addEdge({ ...params, animated: true, style: { stroke: '#94a3b8' } }, eds)),
    [setEdges]
  );

  const onDragOver = useCallback((event: React.DragEvent) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  const onDrop = useCallback(
    (event: React.DragEvent) => {
      event.preventDefault();

      if (!reactFlowWrapper.current || !reactFlowInstance) return;

      const type = event.dataTransfer.getData('application/reactflow') as LayerType;
      
      if (!type) return;

      const position = reactFlowInstance.screenToFlowPosition({
        x: event.clientX,
        y: event.clientY,
      });

      const label = LAYER_DEFINITIONS[type].label;
      const newNode: Node<NodeData> = {
        id: getId(),
        type: 'custom',
        position,
        data: { 
          label: label, 
          type: type, 
          params: LAYER_DEFINITIONS[type].parameters.reduce((acc, p) => ({...acc, [p.name]: p.default}), {}) 
        },
      };

      setNodes((nds) => nds.concat(newNode));
      setSelectedNodeId(newNode.id);
      setIsPropertiesOpen(true); // Open properties panel on drop
      
      // On mobile, close sidebar after dropping
      if (window.innerWidth < 768) {
        setIsSidebarOpen(false);
      }

      addLog(`Added layer: ${label}`, 'info');
    },
    [reactFlowInstance, setNodes, addLog]
  );

  const onNodeClick = useCallback((_: React.MouseEvent, node: Node) => {
    setSelectedNodeId(node.id);
    setIsPropertiesOpen(true);
  }, []);

  const onPaneClick = useCallback(() => {
    setSelectedNodeId(null);
    setIsPropertiesOpen(false);
  }, []);

  // Update node data (params or label) from Properties Panel
  const updateNodeData = (id: string, newData: Partial<NodeData>) => {
    setNodes((nds) =>
      nds.map((node) => {
        if (node.id === id) {
          return {
            ...node,
            data: { ...node.data, ...newData }
          };
        }
        return node;
      })
    );
  };

  const deleteNode = (id: string) => {
    const node = nodes.find(n => n.id === id);
    setNodes((nds) => nds.filter((node) => node.id !== id));
    setEdges((eds) => eds.filter((edge) => edge.source !== id && edge.target !== id));
    setSelectedNodeId(null);
    setIsPropertiesOpen(false);
    if (node) addLog(`Deleted layer: ${node.data.label}`, 'info');
  };

  const handleAPIError = (error: any) => {
      const msg = error.message || String(error);
      addLog(`API Error: ${msg}`, 'error');
      
      // Force disconnect if authentication failed to allow user to re-enter key
      if (msg.includes('API Key') || msg.includes('403') || msg.includes('401') || msg.includes('400')) {
          setIsConnected(false);
          setIsApiKeyModalOpen(true);
          addLog("Disconnected due to invalid API key. Please check your key.", 'warning');
      }
  }

  const handleGeneratePrompt = async () => {
    if (!isConnected) { setIsApiKeyModalOpen(true); return; }
    setIsGeneratingPrompt(true);
    setIsPromptViewerOpen(true);
    addLog("Generating PyTorch code prompt...", 'info');
    try {
        const promptText = await generateRefinedPrompt(nodes, edges);
        setGeneratedPrompt(promptText);
        addLog("Code prompt generated successfully.", 'success');
    } catch (e) {
        setGeneratedPrompt("Failed to generate prompt. See logs for details.");
        handleAPIError(e);
    } finally {
        setIsGeneratingPrompt(false);
    }
  };

  const handleValidate = async () => {
    if (!isConnected) { setIsApiKeyModalOpen(true); return; }
    setValidationMsg("Validating...");
    addLog("Running architecture validation...", 'info');
    try {
        const result = await validateArchitecture(nodes, edges);
        setValidationMsg(result);
        if (result.toLowerCase().includes("valid") && !result.toLowerCase().includes("invalid") && result.length < 50) {
            setTimeout(() => setValidationMsg(null), 5000);
            addLog("Validation passed: Architecture is valid.", 'success');
        } else {
            addLog("Validation issues found.", 'warning');
        }
    } catch (e) {
        setValidationMsg("Validation failed due to API error.");
        handleAPIError(e);
    }
  };

  const handleGetSuggestions = async () => {
    if (!isConnected) { setIsApiKeyModalOpen(true); return; }
    setIsSuggestionsOpen(true);
    setIsSuggestionsLoading(true);
    try {
      const suggestions = await getArchitectureSuggestions(nodes, edges);
      setSuggestionsText(suggestions);
    } catch (error) {
      setSuggestionsText("Failed to get suggestions. API Error.");
      handleAPIError(error);
    } finally {
      setIsSuggestionsLoading(false);
    }
  };

  const handleImplementSuggestions = async () => {
    if (!suggestionsText || isImplementingSuggestions) return;
    setIsImplementingSuggestions(true);
    addLog("AI Agents implementing suggestions...", 'info');
    try {
      const result = await implementArchitectureSuggestions(nodes, edges, suggestionsText);
      if (result && result.nodes) {
         // Fix types and defaults safely
         const processedNodes = result.nodes.map((n: any) => {
            const data = n.data || {};
            const type = data.type || n.type || 'Identity'; // Fallback type
            return {
              ...n,
              type: 'custom',
              data: { 
                ...data, 
                type: type,
                label: data.label || n.label || type, // Safe fallback for label
                params: data.params || {}
              }
            };
         });
         
         const processedEdges = result.edges.map((e: any) => ({
            ...e, animated: true, style: { stroke: '#94a3b8' }
         }));
         
         setNodes(processedNodes);
         setEdges(processedEdges);
         setIsSuggestionsOpen(false); // Close modal on success
         addLog("Implemented AI improvements.", 'success');
      }
    } catch (e) {
      handleAPIError(e);
      addLog("Failed to implement suggestions.", 'error');
    } finally {
      setIsImplementingSuggestions(false);
    }
  };

  const handleCopyLayout = () => {
    const layout = {
      nodes,
      edges
    };
    navigator.clipboard.writeText(JSON.stringify(layout, null, 2));
    setLayoutCopied(true);
    setTimeout(() => setLayoutCopied(false), 2000);
    addLog("Layout JSON copied to clipboard.", 'info');
  };

  const handleApplyAIBuild = (newNodes: any[], newEdges: any[], logMsg?: string) => {
    setNodes(newNodes);
    setEdges(newEdges);
    if (logMsg) {
      addLog(logMsg, 'success');
    }
  };

  const loadTemplate = (templateKey: string) => {
    const template = TEMPLATES[templateKey];
    if (template) {
      // Need to deep clone to avoid reference issues if loaded multiple times
      const clonedNodes = JSON.parse(JSON.stringify(template.nodes));
      const clonedEdges = JSON.parse(JSON.stringify(template.edges));
      
      // Update styling and functional props that aren't in JSON
      const hydratedNodes = clonedNodes.map((n: any) => ({
        ...n,
        data: {
          ...n.data,
          label: LAYER_DEFINITIONS[n.data.type as LayerType]?.label || n.data.label
        }
      }));

      const hydratedEdges = clonedEdges.map((e: any) => ({
        ...e,
        animated: true,
        style: { stroke: '#94a3b8' }
      }));

      setNodes(hydratedNodes);
      setEdges(hydratedEdges);
      setIsTemplateMenuOpen(false);
      
      // Auto open properties to see details of first node
      if (hydratedNodes.length > 0) {
        setSelectedNodeId(hydratedNodes[0].id);
        setIsPropertiesOpen(true);
      }
      addLog(`Loaded template: ${template.name}`, 'info');
    }
  };

  const selectedNode = useMemo(() => 
    nodes.find((n) => n.id === selectedNodeId) || null, 
    [nodes, selectedNodeId]
  );

  return (
    <div className="flex h-screen w-screen bg-slate-950 overflow-hidden">
      <Sidebar 
        onOpenAIBuilder={() => isConnected ? setIsAIBuilderOpen(true) : setIsApiKeyModalOpen(true)}
        onSelectTemplate={(id) => id === 'menu' ? setIsTemplateMenuOpen(true) : loadTemplate(id)}
        onBackToHome={onBackToHome}
        isConnected={isConnected}
        isOpen={isSidebarOpen}
        onToggle={() => setIsSidebarOpen(!isSidebarOpen)}
      />
      
      <div className="flex-1 h-full relative" ref={reactFlowWrapper}>
        <ReactFlow
          nodes={nodes}
          edges={edges}
          onNodesChange={onNodesChange}
          onEdgesChange={onEdgesChange}
          onConnect={onConnect}
          onInit={setReactFlowInstance}
          onDrop={onDrop}
          onDragOver={onDragOver}
          onNodeClick={onNodeClick}
          onPaneClick={onPaneClick}
          nodeTypes={nodeTypes}
          connectionMode={ConnectionMode.Loose}
          fitView
          className="bg-slate-950"
        >
          <Background color="#1e293b" variant={BackgroundVariant.Dots} gap={20} size={1} />
          <Controls className="!bg-slate-800 !border-slate-700 [&>button]:!fill-slate-300 [&>button:hover]:!bg-slate-700 md:bottom-4 md:left-4 bottom-24 left-4" />
          
          {/* Mobile Menu Trigger */}
          <Panel position="top-left" className="md:hidden">
             <button 
               onClick={() => setIsSidebarOpen(true)}
               className="p-2 bg-slate-800/80 backdrop-blur border border-slate-700 rounded-lg text-slate-300 shadow-lg"
             >
               <Menu size={20} />
             </button>
          </Panel>

          {/* Action Toolbar */}
          <Panel position="top-right" className="flex flex-wrap justify-end gap-2 max-w-[80vw]">
            <button 
              onClick={handleCopyLayout}
              className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
              title="Copy Layout JSON"
            >
              {layoutCopied ? <Check size={16} className="text-emerald-500" /> : <Copy size={16} className="text-slate-400" />}
              <span className="hidden md:inline">{layoutCopied ? 'Copied' : 'Copy'}</span>
            </button>
            <button
               onClick={() => setIsApiKeyModalOpen(true)}
               className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
               title="API Key Settings"
            >
              <Key size={16} className={isConnected ? "text-emerald-500" : "text-slate-400"} />
              <span className="hidden md:inline">{isConnected ? 'Key Active' : 'Add Key'}</span>
            </button>
            <button 
              onClick={handleGetSuggestions}
              className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
              title="Get AI Suggestions"
            >
              <Lightbulb size={16} className="text-amber-400" />
              <span className="hidden md:inline">Tips</span>
            </button>
            <button 
              onClick={handleValidate}
              className="flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 text-xs md:text-sm font-medium transition-colors shadow-lg"
              title="Validate Architecture"
            >
              <CheckCircle size={16} className="text-emerald-500" />
              <span className="hidden md:inline">Validate</span>
            </button>
            <button 
              onClick={handleGeneratePrompt}
              className="flex items-center gap-2 px-3 py-2 bg-blue-600/90 hover:bg-blue-500 backdrop-blur rounded-lg text-white text-xs md:text-sm font-medium transition-colors shadow-lg shadow-blue-900/20"
              title="Generate Code Prompt"
            >
              <FileText size={16} />
              <span className="hidden md:inline">Code</span>
            </button>
             {/* Mobile Activity Toggle */}
             <button 
              onClick={() => { setSelectedNodeId(null); setIsPropertiesOpen(true); }}
              className="md:hidden flex items-center gap-2 px-3 py-2 bg-slate-800/80 backdrop-blur hover:bg-slate-700 border border-slate-700 rounded-lg text-slate-200 transition-colors shadow-lg"
              title="System Logs"
            >
              <Activity size={16} className="text-blue-400" />
            </button>
          </Panel>

          {validationMsg && (
            <Panel position="bottom-center" className="mb-20 md:mb-8 w-full flex justify-center px-4">
              <div className="bg-slate-900/95 backdrop-blur border border-slate-700 text-slate-200 px-6 py-4 rounded-xl shadow-2xl max-w-2xl w-full flex flex-col gap-3 animate-in slide-in-from-bottom-5">
                <div className="flex items-start gap-3">
                  <AlertTriangle className="text-amber-500 shrink-0 mt-0.5" size={20} />
                  <div className="flex-1 min-w-0">
                     <h4 className="font-bold text-sm text-slate-300 mb-1">Validation Report</h4>
                     <p className="text-sm whitespace-pre-wrap leading-relaxed text-slate-400 max-h-[30vh] overflow-y-auto scrollbar-thin scrollbar-thumb-slate-700 pr-2">{validationMsg}</p>
                  </div>
                </div>
                
                <div className="flex justify-end gap-3 mt-2">
                   <button 
                    onClick={() => setValidationMsg(null)}
                    className="px-4 py-1.5 text-xs font-medium text-slate-400 hover:text-slate-200 bg-slate-800 hover:bg-slate-700 rounded transition-colors"
                  >
                    Dismiss
                  </button>
                  {!validationMsg.toLowerCase().includes("architecture is valid") && (
                    <button 
                      onClick={() => setIsFixerOpen(true)}
                      className="flex items-center gap-2 px-4 py-1.5 bg-red-600 hover:bg-red-500 text-white rounded text-xs font-medium transition-colors shadow-lg shadow-red-900/20"
                    >
                      <Wrench size={14} />
                      Fix Errors
                    </button>
                  )}
                </div>
              </div>
            </Panel>
          )}

          {/* Template Selection Modal Overlay */}
          {isTemplateMenuOpen && (
             <div className="absolute inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
                <div className="bg-slate-900 border border-slate-700 rounded-xl shadow-2xl w-96 max-w-full flex flex-col max-h-[80vh] overflow-hidden animate-in zoom-in-95 duration-200">
                  <div className="flex justify-between items-center p-6 border-b border-slate-800 shrink-0 bg-slate-900">
                     <h3 className="text-lg font-bold text-white">Select Template</h3>
                     <button onClick={() => setIsTemplateMenuOpen(false)}><X size={20} className="text-slate-500 hover:text-white"/></button>
                  </div>
                  <div className="overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-slate-700">
                    <div className="grid gap-3">
                      {Object.entries(TEMPLATES).map(([key, t]) => (
                        <button 
                          key={key}
                          onClick={() => loadTemplate(key)}
                          className="text-left p-3 rounded bg-slate-800 hover:bg-slate-750 border border-slate-700 hover:border-blue-500/50 transition-all group"
                        >
                           <div className="font-semibold text-slate-200 group-hover:text-blue-400">{t.name}</div>
                           <div className="text-xs text-slate-500">{t.description}</div>
                        </button>
                      ))}
                    </div>
                  </div>
                </div>
             </div>
          )}

        </ReactFlow>
      </div>

      <PropertiesPanel 
        selectedNode={selectedNode} 
        onChange={updateNodeData}
        onDelete={deleteNode}
        onClose={() => { setSelectedNodeId(null); setIsPropertiesOpen(false); }}
        logs={logs}
        isOpen={isPropertiesOpen}
      />

      <CodeViewer 
        isOpen={isPromptViewerOpen} 
        onClose={() => setIsPromptViewerOpen(false)} 
        code={generatedPrompt}
        isLoading={isGeneratingPrompt}
      />
      
      <SuggestionsModal
        isOpen={isSuggestionsOpen}
        onClose={() => setIsSuggestionsOpen(false)}
        suggestions={suggestionsText}
        isLoading={isSuggestionsLoading}
        onImplement={handleImplementSuggestions}
        isImplementing={isImplementingSuggestions}
      />

      <AIBuilderModal 
        isOpen={isAIBuilderOpen}
        onClose={() => setIsAIBuilderOpen(false)}
        onApply={handleApplyAIBuild}
        currentNodes={nodes}
      />

      <FixerModal
        isOpen={isFixerOpen}
        onClose={() => setIsFixerOpen(false)}
        onApply={handleApplyAIBuild}
        errorMsg={validationMsg || ''}
        nodes={nodes}
        edges={edges}
      />

      <ApiKeyModal 
        isOpen={isApiKeyModalOpen}
        onClose={() => setIsApiKeyModalOpen(false)}
        onSuccess={() => setIsConnected(true)}
      />
    </div>
  );
};

export default Builder;
