import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import DeleteIcon from "@mui/icons-material/Delete";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import SaveIcon from "@mui/icons-material/Save";
import TuneIcon from "@mui/icons-material/Tune";
import VisibilityIcon from "@mui/icons-material/Visibility";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import React, { useCallback, useState } from "react";

import { usePromptContext } from "../PromptsPlaygroundContext";
import { PromptType } from "../types";

import ModelParamsDialog from "./ModelParamsDialog";
import PreviewPromptModal from "./PreviewPromptModal";

import { TOUR_IDS } from "@/features/task-tour/selectors";
import { PromptVariableMappingOutput } from "@/lib/api-client/api-client";
import { track, EVENT_NAMES } from "@/services/amplitude";

interface ManagementButtonsProps {
  prompt: PromptType;
  setSavePromptOpen: (open: boolean) => void;
}

const ManagementButtons = ({ prompt, setSavePromptOpen }: ManagementButtonsProps) => {
  const [paramsModelOpen, setParamsModelOpen] = useState<boolean>(false);
  const [previewModalOpen, setPreviewModalOpen] = useState<boolean>(false);
  const { dispatch, state, experimentConfig, handleRunSingleWithConfig, isRunningExperiment } = usePromptContext();

  const handleRunPrompt = useCallback(() => {
    // If in config mode, run with experiment
    if (experimentConfig && handleRunSingleWithConfig) {
      handleRunSingleWithConfig(prompt.id);
      return;
    }

    // Track prompt run event
    track(EVENT_NAMES.PROMPT_RUN, {
      model_provider: prompt.modelProvider,
      model_name: prompt.modelName,
      message_count: prompt.messages.length,
      has_tools: prompt.tools.length > 0,
      is_streaming: prompt.modelParameters?.stream ?? false,
      config_mode: false,
    });

    // Otherwise, run in normal playground mode
    dispatch({
      type: "runPrompt",
      payload: { promptId: prompt.id },
    });
  }, [dispatch, experimentConfig, handleRunSingleWithConfig, prompt]);

  const handleDuplicatePrompt = useCallback(() => {
    dispatch({
      type: "duplicatePrompt",
      payload: { id: prompt.id },
    });
  }, [dispatch, prompt.id]);

  const handleParamsModelOpen = useCallback(() => {
    setParamsModelOpen(true);
  }, []);

  const handlePreviewOpen = useCallback(() => {
    track(EVENT_NAMES.PROMPT_PREVIEW, {
      model_provider: prompt.modelProvider,
      model_name: prompt.modelName,
      message_count: prompt.messages.length,
    });
    setPreviewModalOpen(true);
  }, [prompt]);

  const handleSavePromptOpen = useCallback(() => {
    setSavePromptOpen(true);
  }, [setSavePromptOpen]);

  const handleDeletePrompt = useCallback(() => {
    dispatch({
      type: "deletePrompt",
      payload: { id: prompt.id },
    });
  }, [dispatch, prompt.id]);

  // Check if there are any unset variables
  // In config mode, variables can be empty if they're mapped to dataset columns
  const hasUnsetVariables = React.useMemo(() => {
    if (experimentConfig?.prompt_variable_mapping) {
      // Build a set of mapped variable names
      const mappedVariables = new Set<string>();
      experimentConfig.prompt_variable_mapping.forEach((mapping: PromptVariableMappingOutput) => {
        mappedVariables.add(mapping.variable_name);
      });

      // Check if any unmapped variables are empty
      return Array.from(state.keywords.entries()).some(([key, value]) => {
        const isMapped = mappedVariables.has(key);
        const isEmpty = !value || value.trim() === "";
        return !isMapped && isEmpty; // Only fail if unmapped AND empty
      });
    }

    // Normal mode: all variables must have values
    return Array.from(state.keywords.values()).some((value) => !value || value.trim() === "");
  }, [state.keywords, experimentConfig]);

  // Check if model configuration is complete
  const hasModelConfig = prompt.modelProvider !== "" && prompt.modelName !== "";

  // Every assistant tool_call must be answered by a `tool` message whose
  // tool_call_id matches the call's id. The LLM provider rejects requests
  // with dangling tool_calls, so block the run before we get there.
  const hasUnansweredToolCalls = React.useMemo(() => {
    const answeredCallIds = new Set(
      prompt.messages.filter((message) => message.role === "tool" && message.tool_call_id).map((message) => message.tool_call_id)
    );

    return prompt.messages.some((message) => (message.tool_calls ?? []).some((toolCall) => !answeredCallIds.has(toolCall.id)));
  }, [prompt.messages]);

  // In config mode, disable if experiment is running. In normal mode, disable if prompt is running
  const runDisabled = !hasModelConfig || hasUnsetVariables || hasUnansweredToolCalls || (experimentConfig ? isRunningExperiment : prompt.running);
  const previewDisabled = !hasModelConfig || hasUnsetVariables;
  const needsSave = prompt.needsSave;
  const saveTooltip = needsSave ? (prompt.version ? "Save changes as new version" : "Save as new prompt") : "Save Prompt";

  // Determine the run button tooltip based on disabled state
  let runTooltip = experimentConfig ? "Run Experiment with this Prompt" : "Run Prompt";
  if (!hasModelConfig) {
    if (prompt.modelProvider === "" && prompt.modelName === "") {
      runTooltip = "Please select a model provider and model before running";
    } else if (prompt.modelProvider === "") {
      runTooltip = "Please select a model provider before running";
    } else if (prompt.modelName === "") {
      runTooltip = "Please select a model before running";
    }
  } else if (hasUnsetVariables) {
    runTooltip = "Please fill in all variable values before running";
  } else if (hasUnansweredToolCalls) {
    runTooltip = "Each assistant tool call needs a matching tool message (same tool_call_id) before running";
  } else if (experimentConfig && isRunningExperiment) {
    runTooltip = "An experiment is currently running";
  } else if (prompt.running) {
    runTooltip = "Prompt is currently running";
  }

  // Determine the preview button tooltip
  let previewTooltip = "Preview Rendered Prompt";
  if (!hasModelConfig) {
    if (prompt.modelProvider === "" && prompt.modelName === "") {
      previewTooltip = "Please select a model provider and model before previewing";
    } else if (prompt.modelProvider === "") {
      previewTooltip = "Please select a model provider before previewing";
    } else if (prompt.modelName === "") {
      previewTooltip = "Please select a model before previewing";
    }
  } else if (hasUnsetVariables) {
    previewTooltip = "Please fill in all variable values before previewing";
  }

  return (
    <>
      <Tooltip title={runTooltip} placement="top-start" arrow>
        <span>
          <IconButton aria-label="run prompt" onClick={handleRunPrompt} disabled={runDisabled} loading={prompt.running}>
            <PlayArrowIcon color={runDisabled ? "disabled" : "success"} />
          </IconButton>
        </span>
      </Tooltip>
      <Tooltip title={previewTooltip} placement="top-start" arrow>
        <span>
          <IconButton aria-label="preview prompt" onClick={handlePreviewOpen} disabled={previewDisabled}>
            <VisibilityIcon color={previewDisabled ? "disabled" : "info"} />
          </IconButton>
        </span>
      </Tooltip>
      <Tooltip title="Duplicate Prompt" placement="top-start" arrow>
        <IconButton aria-label="duplicate" onClick={handleDuplicatePrompt} data-tour-id={TOUR_IDS.playgroundDuplicatePrompt}>
          <ContentCopyIcon color="secondary" />
        </IconButton>
      </Tooltip>
      <Tooltip title="Model Parameters" placement="top-start" arrow>
        <IconButton aria-label="model parameters" onClick={handleParamsModelOpen}>
          <TuneIcon color="info" />
        </IconButton>
      </Tooltip>
      <ModelParamsDialog
        open={paramsModelOpen}
        setOpen={setParamsModelOpen}
        promptId={prompt.id}
        name={prompt.name}
        modelParameters={prompt.modelParameters}
      />
      <PreviewPromptModal open={previewModalOpen} setOpen={setPreviewModalOpen} prompt={prompt} />
      <Tooltip title={saveTooltip} placement="top-start" arrow>
        <IconButton
          aria-label="save"
          data-tour-id={TOUR_IDS.playgroundSavePrompt}
          onClick={handleSavePromptOpen}
          sx={{
            ...(needsSave && {
              backgroundColor: "warning.main",
              "&:hover": {
                backgroundColor: "warning.dark",
              },
            }),
          }}
        >
          <SaveIcon sx={{ color: needsSave ? "white" : undefined }} color={needsSave ? undefined : "primary"} />
        </IconButton>
      </Tooltip>
      <Tooltip title="Delete Prompt" placement="top-start" arrow>
        <IconButton aria-label="delete" onClick={handleDeletePrompt}>
          <DeleteIcon color="error" />
        </IconButton>
      </Tooltip>
    </>
  );
};

// Note: We removed the memo optimization because we now depend on global state.keywords
// which isn't available in props, so we can't properly detect changes in arePropsEqual
export default ManagementButtons;
