import { NodeProps, NodeToolbar, Position } from "@xyflow/react";
import { Edit, Play, Wrench } from "lucide-react";
import { memo, useEffect, useState } from "react";

import { useWorkflow } from "@/app/workflow/[workflowId]/contexts/WorkflowContext";
import { ToolBadges } from "@/components/flow/ToolBadges";
import { ToolSelector } from "@/components/flow/ToolSelector";
import { FlowNodeData } from "@/components/flow/types";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { isOSSMode } from "@/lib/utils";

import { NodeContent } from "./common/NodeContent";
import { NodeEditDialog } from "./common/NodeEditDialog";
import { useNodeHandlers } from "./common/useNodeHandlers";

interface StartCallEditFormProps {
    nodeData: FlowNodeData;
    prompt: string;
    setPrompt: (value: string) => void;
    name: string;
    setName: (value: string) => void;
    allowInterrupt: boolean;
    setAllowInterrupt: (value: boolean) => void;
    addGlobalPrompt: boolean;
    setAddGlobalPrompt: (value: boolean) => void;
    detectVoicemail: boolean;
    setDetectVoicemail: (value: boolean) => void;
    delayedStart: boolean;
    setDelayedStart: (value: boolean) => void;
    delayedStartDuration: number;
    setDelayedStartDuration: (value: number) => void;
    toolUuids: string[];
    setToolUuids: (value: string[]) => void;
}

interface StartCallNodeProps extends NodeProps {
    data: FlowNodeData;
}

export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
    const { open, setOpen, handleSaveNodeData } = useNodeHandlers({
        id,
        additionalData: { is_start: true }
    });
    const { saveWorkflow } = useWorkflow();

    // Form state
    const [prompt, setPrompt] = useState(data.prompt ?? "");
    const [name, setName] = useState(data.name);
    const [allowInterrupt, setAllowInterrupt] = useState(data.allow_interrupt ?? true);
    const [addGlobalPrompt, setAddGlobalPrompt] = useState(data.add_global_prompt ?? true);
    const [detectVoicemail, setDetectVoicemail] = useState(data.detect_voicemail ?? false);
    const [delayedStart, setDelayedStart] = useState(data.delayed_start ?? false);
    const [delayedStartDuration, setDelayedStartDuration] = useState(data.delayed_start_duration ?? 2);
    const [toolUuids, setToolUuids] = useState<string[]>(data.tool_uuids ?? []);

    const handleSave = async () => {
        handleSaveNodeData({
            ...data,
            prompt,
            name,
            allow_interrupt: allowInterrupt,
            add_global_prompt: addGlobalPrompt,
            detect_voicemail: detectVoicemail,
            delayed_start: delayedStart,
            delayed_start_duration: delayedStart ? delayedStartDuration : undefined,
            tool_uuids: toolUuids.length > 0 ? toolUuids : undefined,
        });
        setOpen(false);
        // Save the workflow after updating node data with a small delay to ensure state is updated
        setTimeout(async () => {
            await saveWorkflow();
        }, 100);
    };

    // Reset form state when dialog opens
    const handleOpenChange = (newOpen: boolean) => {
        if (newOpen) {
            setPrompt(data.prompt ?? "");
            setName(data.name);
            setAllowInterrupt(data.allow_interrupt ?? true);
            setAddGlobalPrompt(data.add_global_prompt ?? true);
            setDetectVoicemail(data.detect_voicemail ?? false);
            setDelayedStart(data.delayed_start ?? false);
            setDelayedStartDuration(data.delayed_start_duration ?? 3);
            setToolUuids(data.tool_uuids ?? []);
        }
        setOpen(newOpen);
    };

    // Update form state when data changes (e.g., from undo/redo)
    useEffect(() => {
        if (open) {
            setPrompt(data.prompt ?? "");
            setName(data.name);
            setAllowInterrupt(data.allow_interrupt ?? true);
            setAddGlobalPrompt(data.add_global_prompt ?? true);
            setDetectVoicemail(data.detect_voicemail ?? false);
            setDelayedStart(data.delayed_start ?? false);
            setDelayedStartDuration(data.delayed_start_duration ?? 3);
            setToolUuids(data.tool_uuids ?? []);
        }
    }, [data, open]);

    return (
        <>
            <NodeContent
                selected={selected}
                invalid={data.invalid}
                selected_through_edge={data.selected_through_edge}
                hovered_through_edge={data.hovered_through_edge}
                title="Start Call"
                icon={<Play />}
                nodeType="start"
                hasSourceHandle={true}
                onDoubleClick={() => setOpen(true)}
                nodeId={id}
            >
                <p className="text-sm text-muted-foreground line-clamp-5 leading-relaxed">
                    {data.prompt || 'No prompt configured'}
                </p>
                {data.tool_uuids && data.tool_uuids.length > 0 && (
                    <div className="mt-3 pt-3 border-t border-border/50">
                        <div className="flex items-center gap-1.5 text-xs text-muted-foreground mb-2">
                            <Wrench className="h-3 w-3" />
                            <span>Tools:</span>
                        </div>
                        <ToolBadges toolUuids={data.tool_uuids} />
                    </div>
                )}
            </NodeContent>

            <NodeToolbar isVisible={selected} position={Position.Right}>
                <Button onClick={() => setOpen(true)} variant="outline" size="icon">
                    <Edit />
                </Button>
            </NodeToolbar>

            <NodeEditDialog
                open={open}
                onOpenChange={handleOpenChange}
                nodeData={data}
                title="Start Call"
                onSave={handleSave}
            >
                {open && (
                    <StartCallEditForm
                        nodeData={data}
                        prompt={prompt}
                        setPrompt={setPrompt}
                        name={name}
                        setName={setName}
                        allowInterrupt={allowInterrupt}
                        setAllowInterrupt={setAllowInterrupt}
                        addGlobalPrompt={addGlobalPrompt}
                        setAddGlobalPrompt={setAddGlobalPrompt}
                        detectVoicemail={detectVoicemail}
                        setDetectVoicemail={setDetectVoicemail}
                        delayedStart={delayedStart}
                        setDelayedStart={setDelayedStart}
                        delayedStartDuration={delayedStartDuration}
                        setDelayedStartDuration={setDelayedStartDuration}
                        toolUuids={toolUuids}
                        setToolUuids={setToolUuids}
                    />
                )}
            </NodeEditDialog>
        </>
    );
});

const StartCallEditForm = ({
    prompt,
    setPrompt,
    name,
    setName,
    allowInterrupt,
    setAllowInterrupt,
    addGlobalPrompt,
    setAddGlobalPrompt,
    detectVoicemail,
    setDetectVoicemail,
    delayedStart,
    setDelayedStart,
    delayedStartDuration,
    setDelayedStartDuration,
    toolUuids,
    setToolUuids,
}: StartCallEditFormProps) => {
    return (
        <div className="grid gap-2">
            <Label>Name</Label>
            <Label className="text-xs text-muted-foreground">
                The name of the agent that will be used to identify the agent in the call logs. It should be short and should identify the step in the call.
            </Label>
            <Input
                value={name}
                onChange={(e) => setName(e.target.value)}
            />

            <Label>Prompt</Label>
            <Label className="text-xs text-muted-foreground">
                Enter the prompt for the agent. This will be used to generate the agent&apos;s response. Prompt engineering&apos;s best practices apply.
            </Label>
            <Textarea
                value={prompt}
                onChange={(e) => setPrompt(e.target.value)}
                className="min-h-[100px] max-h-[300px] resize-none"
                style={{
                    overflowY: 'auto'
                }}
                placeholder="Enter a prompt"
            />
            <div className="flex items-center space-x-2">
                <Switch id="allow-interrupt" checked={allowInterrupt} onCheckedChange={setAllowInterrupt} />
                <Label htmlFor="allow-interrupt">Allow Interruption</Label>
                <Label className="text-xs text-muted-foreground">
                    Whether you would like user to be able to interrupt the bot.
                </Label>
            </div>
            <div className="flex items-center space-x-2">
                <Switch
                    id="add-global-prompt"
                    checked={addGlobalPrompt}
                    onCheckedChange={setAddGlobalPrompt}
                />
                <Label htmlFor="add-global-prompt">
                    Add Global Prompt
                </Label>
            </div>
            {!isOSSMode() && (
                <div className="flex items-center space-x-2">
                    <Switch
                        id="detect-voicemail"
                        checked={detectVoicemail}
                        onCheckedChange={setDetectVoicemail}
                    />
                    <Label htmlFor="detect-voicemail">
                        Detect Voicemail
                    </Label>
                    <Label className="text-xs text-muted-foreground">
                        Automatically detect and end call if voicemail is reached.
                    </Label>
                </div>
            )}
            <div className="flex flex-col space-y-2">
                <div className="flex items-center space-x-2">
                    <Switch
                        id="delayed-start"
                        checked={delayedStart}
                        onCheckedChange={setDelayedStart}
                    />
                    <Label htmlFor="delayed-start">
                        Delayed Start
                    </Label>
                    <Label className="text-xs text-muted-foreground">
                        Introduce a delay before the agent starts speaking.
                    </Label>
                </div>
                {delayedStart && (
                    <div className="ml-6 flex items-center space-x-2">
                        <Label htmlFor="delay-duration" className="text-sm">
                            Delay (seconds):
                        </Label>
                        <Input
                            id="delay-duration"
                            type="number"
                            step="0.1"
                            min="0.1"
                            max="10"
                            value={delayedStartDuration}
                            onChange={(e) => setDelayedStartDuration(parseFloat(e.target.value) || 3)}
                            className="w-20"
                        />
                    </div>
                )}
            </div>

            {/* Tools Section */}
            <div className="pt-4 border-t mt-4">
                <ToolSelector
                    value={toolUuids}
                    onChange={setToolUuids}
                    description="Select tools that the agent can invoke during this conversation step."
                />
            </div>
        </div>
    );
};

StartCall.displayName = "StartCall";
