"use client";

import { useState, useCallback } from "react";
import {
  ReactFlow,
  Controls,
  Background,
  applyNodeChanges,
  applyEdgeChanges,
  addEdge,
  Node,
  Edge,
  NodeChange,
  EdgeChange,
  Connection,
  Panel,
  Handle,
  Position,
} from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ArrowLeft, Save, X } from "lucide-react";
import Link from "next/link";
import { toast } from "sonner";

const initialNodes: Node[] = [
  {
    id: "1",
    data: { label: "Initial Screen" },
    position: { x: 250, y: 150 },
    type: "screen",
  },
];

const ScreenNode = ({ data }: any) => {
  return (
    <div className="bg-card border-2 border-indigo-500 rounded-lg p-3 shadow-md min-w-[150px] text-foreground">
      <Handle type="target" position={Position.Top} className="w-2 h-2" />
      <div className="font-medium text-sm">{data.label}</div>
      <div className="text-[10px] text-muted-foreground mt-1">Screen</div>
      <Handle type="source" position={Position.Bottom} className="w-2 h-2" />
    </div>
  );
};

const FunctionNode = ({ data }: any) => {
  return (
    <div className="bg-card border-2 border-amber-500 rounded-lg p-3 shadow-md min-w-[150px] text-foreground">
      <Handle type="target" position={Position.Top} className="w-2 h-2" />
      <div className="font-medium text-sm">{data.label}</div>
      <div className="text-[10px] text-muted-foreground mt-1">Function / Action</div>
      <Handle type="source" position={Position.Bottom} className="w-2 h-2" />
    </div>
  );
};

const nodeTypes = {
  screen: ScreenNode,
  function: FunctionNode,
};

const initialEdges: Edge[] = [];

type Flow = any; // Will use the passed down prisma type

export function FlowBuilderClient({ flow }: { flow: Flow }) {
  // If draftGraph is available in flow, use it. Otherwise, use initialNodes
  const savedGraph = flow.draftGraph ? (typeof flow.draftGraph === 'string' ? JSON.parse(flow.draftGraph) : flow.draftGraph) : null;
  
  const [nodes, setNodes] = useState<Node[]>(savedGraph?.nodes || initialNodes);
  const [edges, setEdges] = useState<Edge[]>(savedGraph?.edges || initialEdges);
  const [saving, setSaving] = useState(false);

  // Properties Editor State
  const [selectedNode, setSelectedNode] = useState<Node | null>(null);
  const [nodeLabel, setNodeLabel] = useState("");
  const [nodeFunctionType, setNodeFunctionType] = useState("send_message");

  const onNodesChange = useCallback(
    (changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
    []
  );
  const onEdgesChange = useCallback(
    (changes: EdgeChange[]) => setEdges((eds) => applyEdgeChanges(changes, eds)),
    []
  );
  const onConnect = useCallback(
    (params: Connection) => setEdges((eds) => addEdge(params, eds)),
    []
  );

  const onNodeDoubleClick = useCallback((_: React.MouseEvent, node: Node) => {
    setSelectedNode(node);
    setNodeLabel((node.data?.label as string) || "");
    if (node.type === "function") {
      setNodeFunctionType((node.data?.functionType as string) || "send_message");
    }
  }, []);

  const handleSaveNodeProperties = () => {
    if (!selectedNode) return;
    setNodes((nds) =>
      nds.map((n) => {
        if (n.id === selectedNode.id) {
          return {
            ...n,
            data: {
              ...n.data,
              label: nodeLabel,
              ...(n.type === "function" ? { functionType: nodeFunctionType } : {}),
            },
          };
        }
        return n;
      })
    );
    setSelectedNode(null);
  };

  async function handleSave() {
    setSaving(true);
    try {
      const draftGraph = JSON.stringify({ nodes, edges });
      const res = await fetch(`/api/flows/${flow.id}/save`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ draftGraph }),
      });
      if (!res.ok) throw new Error("Failed to save");
      toast.success("Draft saved successfully.");
    } catch (e) {
      toast.error("Failed to save draft.");
    } finally {
      setSaving(false);
    }
  }

  function addScreen() {
    const newNode: Node = {
      id: Math.random().toString(36).substr(2, 9),
      data: { label: "New Screen" },
      position: { x: Math.random() * 200 + 100, y: Math.random() * 200 + 100 },
      type: "screen",
    };
    setNodes((nds) => [...nds, newNode]);
  }

  function addFunction() {
    const newNode: Node = {
      id: Math.random().toString(36).substr(2, 9),
      data: { label: "New Function" },
      position: { x: Math.random() * 200 + 100, y: Math.random() * 200 + 100 },
      type: "function",
    };
    setNodes((nds) => [...nds, newNode]);
  }

  return (
    <div className="flex h-[calc(100vh-6rem)] flex-col border border-border rounded-xl overflow-hidden bg-card">
      <div className="flex h-14 items-center justify-between border-b border-border bg-muted/50 px-4 shrink-0">
        <div className="flex items-center gap-4">
          <Link href="/flows" className="text-muted-foreground hover:text-foreground transition-colors">
            <ArrowLeft className="h-5 w-5" />
          </Link>
          <div>
            <h2 className="font-semibold text-foreground">{flow.name}</h2>
            <p className="text-[10px] text-muted-foreground">ID: {flow.metaFlowId}</p>
          </div>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="outline" onClick={addScreen}>
            Add Screen
          </Button>
          <Button variant="outline" onClick={addFunction}>
            Add Function
          </Button>
          <Button onClick={handleSave} disabled={saving}>
            <Save className="mr-2 h-4 w-4" />
            {saving ? "Saving..." : "Save Draft"}
          </Button>
        </div>
      </div>
      
      <div className="flex flex-1 relative overflow-hidden">
        <div className="flex-1 relative">
          <ReactFlow
            nodes={nodes}
            edges={edges}
            onNodesChange={onNodesChange}
            onEdgesChange={onEdgesChange}
            onConnect={onConnect}
            onNodeDoubleClick={onNodeDoubleClick}
            nodeTypes={nodeTypes}
            fitView
          >
            <Background color="#ccc" gap={16} />
            <Controls />
            <Panel 
              position="top-right" 
              className={`bg-card p-4 rounded-lg shadow-sm border border-border w-64 m-4 transition-opacity ${selectedNode ? 'opacity-0 pointer-events-none' : 'opacity-100 pointer-events-none'}`}
            >
              <h3 className="font-medium text-sm mb-2 pointer-events-auto">Instructions</h3>
              <p className="text-xs text-muted-foreground pointer-events-auto">
                Drag from handles to connect screens. You can freely arrange the canvas. Double click a node to edit its properties.
              </p>
            </Panel>
          </ReactFlow>
        </div>

        {selectedNode && (
          <div className="w-80 border-l border-border bg-card p-4 flex flex-col shadow-lg z-10 absolute right-0 top-0 bottom-0">
            <div className="flex items-center justify-between mb-4 pb-2 border-b border-border">
              <h3 className="font-medium text-foreground">Edit Node Properties</h3>
              <Button variant="ghost" size="icon" onClick={() => setSelectedNode(null)} className="h-8 w-8">
                <X className="h-4 w-4" />
              </Button>
            </div>
            
            <div className="flex-1 space-y-4">
              <div className="space-y-2">
                <label className="text-sm font-medium text-foreground">Node Label</label>
                <Input 
                  value={nodeLabel} 
                  onChange={(e) => setNodeLabel(e.target.value)} 
                  placeholder="Enter node label..."
                />
              </div>
              
              {selectedNode.type === "function" && (
                <div className="space-y-2 mt-4">
                  <label className="text-sm font-medium text-foreground">Function Type</label>
                  <select 
                    value={nodeFunctionType}
                    onChange={(e) => setNodeFunctionType(e.target.value)}
                    className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
                  >
                    <option value="send_message">Send Message</option>
                    <option value="add_tag">Add Tag</option>
                    <option value="remove_tag">Remove Tag</option>
                    <option value="assign_agent">Assign to Agent</option>
                    <option value="update_field">Update Custom Field</option>
                  </select>
                </div>
              )}
            </div>

            <div className="pt-4 border-t border-border mt-auto">
              <Button onClick={handleSaveNodeProperties} className="w-full">
                Apply Changes
              </Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
