import { MustacheHighlightedTextField } from "@arthur/shared-components";
import CloseIcon from "@mui/icons-material/Close";
import LocalOfferIcon from "@mui/icons-material/LocalOffer";
import SettingsIcon from "@mui/icons-material/Settings";
import Alert from "@mui/material/Alert";
import AlertTitle from "@mui/material/AlertTitle";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Chip from "@mui/material/Chip";
import CircularProgress from "@mui/material/CircularProgress";
import Dialog from "@mui/material/Dialog";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import Divider from "@mui/material/Divider";
import FormControlLabel from "@mui/material/FormControlLabel";
import IconButton from "@mui/material/IconButton";
import Paper from "@mui/material/Paper";
import Popover from "@mui/material/Popover";
import Radio from "@mui/material/Radio";
import TextField from "@mui/material/TextField";
import Typography from "@mui/material/Typography";
import { useSnackbar } from "notistack";
import { useState, useCallback } from "react";
import { useNavigate } from "react-router-dom";

import { useAddTagToPromptVersionMutation } from "../hooks/useAddTagToPromptVersionMutation";
import { useDeleteTagFromPromptVersionMutation } from "../hooks/useDeleteTagFromPromptVersionMutation";
import type { PromptDetailViewProps } from "../types";

import { useDisplaySettings } from "@/contexts/DisplaySettingsContext";
import { TOUR_IDS, tourDataAttr } from "@/features/task-tour/selectors";
import { dispatchTourEvent, TASK_TOUR_EVENTS } from "@/features/task-tour/tourEvents";
import { useApi } from "@/hooks/useApi";
import { useCreateNotebookMutation, useSetNotebookStateMutation } from "@/hooks/useNotebooks";
import { formatDateInTimezone } from "@/utils/formatters";

const PromptDetailView = ({
  promptData,
  isLoading,
  error,
  promptName,
  version,
  latestVersion,
  taskId,
  onClose,
  onRefetch,
}: PromptDetailViewProps) => {
  const [tagAnchorEl, setTagAnchorEl] = useState<HTMLButtonElement | null>(null);
  const [newTag, setNewTag] = useState("");
  const [tagError, setTagError] = useState("");
  const [promoteToProduction, setPromoteToProduction] = useState(false);
  const [isConfigModalOpen, setIsConfigModalOpen] = useState(false);

  const addTagMutation = useAddTagToPromptVersionMutation();
  const deleteTagMutation = useDeleteTagFromPromptVersionMutation();
  const apiClient = useApi();
  const navigate = useNavigate();
  const { timezone, use24Hour } = useDisplaySettings();
  const { enqueueSnackbar } = useSnackbar();
  const setNotebookStateMutation = useSetNotebookStateMutation();

  const createNotebookMutation = useCreateNotebookMutation(taskId);

  const handleAddTagClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
    setTagAnchorEl(event.currentTarget);
    setNewTag("");
    setTagError("");
    setPromoteToProduction(false);
  }, []);

  const handleAddTagClose = useCallback(() => {
    setTagAnchorEl(null);
    setNewTag("");
    setTagError("");
    setPromoteToProduction(false);
    dispatchTourEvent(TASK_TOUR_EVENTS.promptPromoted);
  }, []);

  const handleAddTagConfirm = useCallback(async () => {
    // Check if user is trying to do anything at all
    if (!newTag.trim() && !promoteToProduction) {
      setTagError("Please enter a tag or select 'Promote to Production'");
      return;
    }

    // Check for reserved tag name if a tag was entered
    if (newTag.trim() && newTag.trim().toLowerCase() === "latest") {
      setTagError("'latest' is a reserved keyword and cannot be used as a tag");
      return;
    }

    // Check for duplicate tag if a tag was entered
    if (newTag.trim() && promptData?.tags?.includes(newTag.trim())) {
      setTagError("This tag already exists");
      return;
    }

    if (!taskId || version === null) return;

    try {
      // Add the user-entered tag if provided
      if (newTag.trim()) {
        await addTagMutation.mutateAsync({
          promptName,
          promptVersion: version.toString(),
          taskId,
          data: { tag: newTag.trim() },
        });
      }

      // If promote to production is checked, add the "production" tag
      if (promoteToProduction) {
        await addTagMutation.mutateAsync({
          promptName,
          promptVersion: version.toString(),
          taskId,
          data: { tag: "production" },
        });
      }

      setTagAnchorEl(null);
      setNewTag("");
      setTagError("");
      setPromoteToProduction(false);
      onRefetch?.();
      dispatchTourEvent(TASK_TOUR_EVENTS.promptPromoted);
    } catch (err) {
      setTagError(err instanceof Error ? err.message : "Failed to add tag");
    }
  }, [newTag, promoteToProduction, promptData?.tags, taskId, version, promptName, addTagMutation, onRefetch]);

  const tagPopoverOpen = Boolean(tagAnchorEl);

  const handleDeleteTag = useCallback(
    async (tag: string) => {
      if (!taskId || version === null) return;

      try {
        await deleteTagMutation.mutateAsync({
          promptName,
          promptVersion: version.toString(),
          tag,
          taskId,
        });
        onRefetch?.();
      } catch (err) {
        console.error("Failed to delete tag:", err);
      }
    },
    [taskId, version, promptName, deleteTagMutation, onRefetch]
  );

  const handleOpenInPlayground = useCallback(async () => {
    if (!taskId || version === null || !apiClient) return;

    try {
      const notebookName = `${promptName} v${version}`;

      // Search for a notebook with this exact name using the name filter
      const response = await apiClient.api.listNotebooksApiV1TasksTaskIdNotebooksGet({
        taskId,
        page: 0,
        page_size: 1,
        name: notebookName,
      });

      const existingNotebook = response.data.data?.[0];
      let targetNotebookId: string;

      if (existingNotebook && existingNotebook.name === notebookName) {
        targetNotebookId = existingNotebook.id;

        const existingStateResponse = await apiClient.api.getNotebookStateApiV1NotebooksNotebookIdStateGet(targetNotebookId);
        const existingState = existingStateResponse.data;

        const alreadyHasPrompt = existingState.prompt_configs?.some(
          (p: { type?: string; name?: string; version?: number }) => p.type === "saved" && p.name === promptName && p.version === version
        );

        if (!alreadyHasPrompt) {
          await setNotebookStateMutation.mutateAsync({
            notebookId: targetNotebookId,
            request: {
              state: {
                ...existingState,
                prompt_configs: [...(existingState.prompt_configs ?? []), { type: "saved" as const, name: promptName, version }],
              },
            },
          });
        }
      } else {
        const notebook = await createNotebookMutation.mutateAsync({
          name: notebookName,
          description: `Playground for prompt ${promptName} version ${version}`,
        });
        targetNotebookId = notebook.id;

        const existingStateResponse = await apiClient.api.getNotebookStateApiV1NotebooksNotebookIdStateGet(targetNotebookId);
        const existingState = existingStateResponse.data;

        await setNotebookStateMutation.mutateAsync({
          notebookId: targetNotebookId,
          request: {
            state: {
              ...existingState,
              prompt_configs: [{ type: "saved" as const, name: promptName, version }],
            },
          },
        });
      }

      // Navigate with prompt params so the playground can also fetch the prompt directly
      const url = `/tasks/${taskId}/playgrounds/prompts?notebookId=${targetNotebookId}&promptName=${encodeURIComponent(promptName)}&version=${version}`;
      navigate(url);
      dispatchTourEvent(TASK_TOUR_EVENTS.promptOpenedInPlayground);
    } catch (err) {
      console.error("Failed to open in playground:", err);
      enqueueSnackbar("Failed to open in playground", { variant: "error" });
    }
  }, [taskId, promptName, version, apiClient, createNotebookMutation, setNotebookStateMutation, navigate, enqueueSnackbar]);

  if (isLoading) {
    return (
      <Box
        sx={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100%",
        }}
      >
        <CircularProgress />
      </Box>
    );
  }

  if (error) {
    return (
      <Box sx={{ p: 3 }}>
        <Alert severity="error">Error loading prompt: {error.message}</Alert>
      </Box>
    );
  }

  if (!promptData) {
    return (
      <Box sx={{ p: 3 }}>
        <Alert severity="info">No prompt data available</Alert>
      </Box>
    );
  }

  return (
    <Box sx={{ p: 3, height: "100%", display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 3, flexShrink: 0 }}>
        <Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap", minWidth: 0, overflow: "hidden" }}>
          <Typography variant="h5" noWrap sx={{ fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", maxWidth: "100%" }}>
            {promptName}
          </Typography>
          {version !== null && <Chip label={`Version ${version}`} size="small" sx={{ height: 24 }} />}
          {version !== null && version === latestVersion && <Chip label="Latest" size="small" color="default" sx={{ height: 24 }} />}
          {promptData.tags && promptData.tags.length > 0 && (
            <Box sx={{ display: "flex", gap: 0.5, flexWrap: "wrap" }}>
              {promptData.tags.map((tag) => {
                const isProduction = tag.toLowerCase() === "production";
                return (
                  <Chip
                    key={tag}
                    label={tag}
                    size="small"
                    onDelete={() => handleDeleteTag(tag)}
                    sx={{ height: 24 }}
                    color={isProduction ? "success" : "primary"}
                    variant={isProduction ? "filled" : "outlined"}
                  />
                );
              })}
            </Box>
          )}
          {version !== null && (
            <IconButton size="small" onClick={handleAddTagClick} aria-label="Add tag" data-tour-id={TOUR_IDS.promptAddTag}>
              <LocalOfferIcon fontSize="small" />
            </IconButton>
          )}
        </Box>
        <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
          {!promptData.deleted_at && version !== null && (
            <Button
              variant="outlined"
              size="small"
              onClick={handleOpenInPlayground}
              disabled={createNotebookMutation.isPending || setNotebookStateMutation.isPending}
              data-tour-id={TOUR_IDS.promptOpenInPlayground}
              sx={{ minWidth: 80 }}
            >
              {createNotebookMutation.isPending || setNotebookStateMutation.isPending ? "Opening..." : "Open in Playground"}
            </Button>
          )}
          {onClose && (
            <IconButton onClick={onClose} aria-label="Close">
              <CloseIcon />
            </IconButton>
          )}
        </Box>
      </Box>

      <Box sx={{ display: "flex", flexDirection: "column", gap: 3, flex: 1, minHeight: 0, overflow: "auto" }}>
        <Paper sx={{ p: 3, flexShrink: 0 }}>
          <Typography variant="h6" sx={{ mb: 2, fontWeight: 600 }}>
            Metadata
          </Typography>
          {promptData.model_provider === "empty" && (
            <Alert severity="warning" sx={{ mb: 2 }}>
              <AlertTitle>Model not configured</AlertTitle>
              This prompt is using the <strong>Empty</strong> placeholder model. Update the model provider and model name before running this prompt.
            </Alert>
          )}
          <Box sx={{ display: "flex", gap: 4, flexWrap: "wrap", alignItems: "flex-start" }}>
            <Box>
              <Typography variant="caption" color="text.secondary">
                Model Provider
              </Typography>
              <Typography variant="body1" sx={{ fontWeight: 500 }}>
                {promptData.model_provider}
              </Typography>
            </Box>
            <Box>
              <Typography variant="caption" color="text.secondary">
                Model Name
              </Typography>
              <Typography variant="body1" sx={{ fontWeight: 500 }}>
                {promptData.model_name}
              </Typography>
            </Box>
            <Box>
              <Typography variant="caption" color="text.secondary">
                Created At
              </Typography>
              <Typography variant="body1" sx={{ fontWeight: 500 }}>
                {promptData.created_at ? formatDateInTimezone(promptData.created_at, timezone, { hour12: !use24Hour }) : "N/A"}
              </Typography>
            </Box>
            {promptData.deleted_at && (
              <Box>
                <Typography variant="caption" color="text.secondary">
                  Deleted At
                </Typography>
                <Typography variant="body1" sx={{ fontWeight: 500, color: "error.main" }}>
                  {formatDateInTimezone(promptData.deleted_at, timezone, { hour12: !use24Hour })}
                </Typography>
              </Box>
            )}
            {promptData.config && (
              <Box>
                <Typography variant="caption" color="text.secondary" sx={{ display: "block" }}>
                  Configuration
                </Typography>
                <Button
                  variant="text"
                  size="small"
                  startIcon={<SettingsIcon />}
                  onClick={() => setIsConfigModalOpen(true)}
                  sx={{
                    p: 0,
                    minWidth: 0,
                    justifyContent: "flex-start",
                    fontWeight: 500,
                    textTransform: "none",
                    "&:hover": {
                      backgroundColor: "transparent",
                      textDecoration: "underline",
                    },
                  }}
                >
                  View Config
                </Button>
              </Box>
            )}
          </Box>
        </Paper>

        <Paper sx={{ p: 3, display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }}>
          <Typography variant="h6" sx={{ mb: 2, fontWeight: 600 }}>
            Messages
          </Typography>
          <Box
            sx={{
              flex: 1,
              minHeight: 0,
              display: "flex",
              flexDirection: "column",
              "& .MuiTextField-root": {
                flex: 1,
                display: "flex",
                flexDirection: "column",
              },
              "& .MuiInputBase-root": {
                flex: 1,
                height: "100%",
                alignItems: "flex-start",
              },
              "& .MuiInputBase-input": {
                height: "100% !important",
                overflow: "auto !important",
              },
            }}
          >
            <MustacheHighlightedTextField
              value={JSON.stringify(promptData.messages, null, 2)}
              onChange={() => {}} // Read-only, no-op
              disabled
              multiline
              minRows={4}
              size="small"
            />
          </Box>
        </Paper>
      </Box>

      <Popover
        open={tagPopoverOpen}
        anchorEl={tagAnchorEl}
        onClose={handleAddTagClose}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left",
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "left",
        }}
        slotProps={{
          paper: {
            ...tourDataAttr(TOUR_IDS.promptTagsPopover),
          },
        }}
      >
        <Box sx={{ p: 2, minWidth: 300 }}>
          <Typography variant="subtitle1" sx={{ mb: 0.5, fontWeight: 600 }}>
            Prompt Tags
          </Typography>
          <Typography variant="caption" color="text.secondary" sx={{ mb: 2, display: "block" }}>
            Production status and tags to easily identify your prompts.
          </Typography>

          <Divider sx={{ mb: 2 }} />

          <Typography variant="body2" sx={{ mb: 1, fontWeight: 600 }}>
            Promote to Production
          </Typography>
          <Box sx={{ mb: 2 }}>
            <FormControlLabel
              control={<Radio checked={promoteToProduction} onChange={(e) => setPromoteToProduction(e.target.checked)} size="small" />}
              label={<Typography variant="caption">Mark this version as production</Typography>}
            />
          </Box>

          <Divider sx={{ mb: 2 }} />

          <Typography variant="body2" sx={{ mb: 1, fontWeight: 600 }}>
            Custom Tag (Optional)
          </Typography>
          <TextField
            autoFocus
            size="small"
            label="Tag Name"
            type="text"
            fullWidth
            variant="outlined"
            value={newTag}
            onChange={(e) => {
              setNewTag(e.target.value);
              setTagError("");
            }}
            error={!!tagError}
            helperText={tagError}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                handleAddTagConfirm();
              }
            }}
            sx={{ mb: 1.5 }}
          />

          <Box sx={{ display: "flex", gap: 1, justifyContent: "flex-end" }}>
            <Button size="small" onClick={handleAddTagClose} disabled={addTagMutation.isPending}>
              Cancel
            </Button>
            <Button
              size="small"
              onClick={handleAddTagConfirm}
              variant="contained"
              disabled={addTagMutation.isPending}
              startIcon={addTagMutation.isPending ? <CircularProgress size={14} /> : null}
            >
              {addTagMutation.isPending ? "Adding..." : "Save"}
            </Button>
          </Box>
        </Box>
      </Popover>

      <Dialog open={isConfigModalOpen} onClose={() => setIsConfigModalOpen(false)} maxWidth="md" fullWidth>
        <DialogTitle>Configuration</DialogTitle>
        <DialogContent>
          <Box
            component="pre"
            sx={{
              backgroundColor: "action.hover",
              p: 2,
              borderRadius: 1,
              overflow: "auto",
              fontSize: "0.875rem",
              fontFamily: "monospace",
              maxHeight: 500,
              m: 0,
            }}
          >
            {promptData?.config ? JSON.stringify(promptData.config, null, 2) : "No configuration available"}
          </Box>
        </DialogContent>
      </Dialog>
    </Box>
  );
};

export default PromptDetailView;
