import { formatRelative } from "date-fns/formatRelative";

import type { TokenProps, ViewProps } from "@phoenix/components";
import { Flex, Text, Token, View } from "@phoenix/components";
import { AnnotatorKindToken } from "@phoenix/components/trace/AnnotatorKindToken";
import { UserPicture } from "@phoenix/components/user/UserPicture";
import { formatFloat } from "@phoenix/utils/numberFormatUtils";

import { DocumentAnnotationActionMenu } from "./DocumentAnnotationActionMenu";
import {
  DocumentAnnotationForm,
  type DocumentAnnotationFormData,
} from "./DocumentAnnotationForm";

const DANGER_ANNOTATION_LABELS = ["irrelevant", "unrelated"];
const ANNOTATOR_KINDS = new Set(["HUMAN", "LLM", "CODE"] as const);
type AnnotatorKind = "HUMAN" | "LLM" | "CODE";

function isAnnotatorKind(value: string): value is AnnotatorKind {
  return ANNOTATOR_KINDS.has(value as AnnotatorKind);
}

export type DocumentAnnotation = {
  id: string;
  annotatorKind: string;
  documentPosition: number;
  name: string;
  label: string | null;
  score: number | null;
  explanation: string | null;
  createdAt: string;
  updatedAt: string;
  user: { username: string; profilePictureUrl: string | null } | null;
};

export function DocumentAnnotationItem({
  documentAnnotation,
  spanNodeId,
  documentPosition,
  borderColor,
  tokenColor,
  canAnnotate,
  editingAnnotation,
  existingAnnotationNames,
  nowEpochMs,
  onEdit,
  onSaved,
  onCancel,
}: {
  /** The document annotation data to display */
  documentAnnotation: DocumentAnnotation;
  /** The relay node ID of the parent span */
  spanNodeId: string;
  /** The zero-based position of the document within the span's retrieval list */
  documentPosition: number;
  /** Border color token applied to the item's card container */
  borderColor: ViewProps["borderColor"];
  /** Color token used for label and score badges */
  tokenColor: TokenProps["color"];
  /** Whether the current user has permission to annotate */
  canAnnotate: boolean;
  /** The annotation currently being edited, or null if none */
  editingAnnotation: DocumentAnnotationFormData | null;
  /** Names of existing annotations, used to prevent duplicate names in the form */
  existingAnnotationNames: string[];
  /** Reference epoch timestamp (ms) used for relative date formatting */
  nowEpochMs: number;
  /** Called when the user initiates editing of this annotation */
  onEdit: (annotation: DocumentAnnotationFormData) => void;
  /** Called after an annotation is successfully saved */
  onSaved: () => void;
  /** Called when the user cancels editing */
  onCancel: () => void;
}) {
  const evalTokenColor =
    documentAnnotation.label &&
    DANGER_ANNOTATION_LABELS.includes(documentAnnotation.label)
      ? "var(--global-color-danger)"
      : tokenColor;

  const isEditing =
    editingAnnotation != null && editingAnnotation.id === documentAnnotation.id;

  if (isEditing) {
    return (
      <View borderWidth="thin" borderColor={borderColor} borderRadius="medium">
        <DocumentAnnotationForm
          spanNodeId={spanNodeId}
          documentPosition={documentPosition}
          existingAnnotation={editingAnnotation}
          existingAnnotationNames={existingAnnotationNames.filter(
            (n) => n !== editingAnnotation.name
          )}
          onSaved={onSaved}
          onCancel={onCancel}
        />
      </View>
    );
  }

  const hasDetails =
    documentAnnotation.label != null ||
    typeof documentAnnotation.score === "number" ||
    isAnnotatorKind(documentAnnotation.annotatorKind);

  return (
    <View
      padding="size-200"
      borderWidth="thin"
      borderColor={borderColor}
      borderRadius="medium"
    >
      <Flex direction="column" gap="size-100">
        <Flex
          direction="row"
          alignItems="center"
          justifyContent="space-between"
          gap="size-100"
        >
          <Text weight="heavy" elementType="h5">
            {documentAnnotation.name}
          </Text>
          <Flex direction="row" gap="size-75" alignItems="center" wrap="wrap">
            <Flex direction="row" gap="size-50" alignItems="center">
              <UserPicture
                name={documentAnnotation.user?.username || "system"}
                profilePictureUrl={
                  documentAnnotation.user?.profilePictureUrl || null
                }
                size={16}
              />
              <Text size="XS" color="text-300">
                {documentAnnotation.user?.username || "system"}
              </Text>
            </Flex>
            <Text color="text-300" size="XS">
              {formatRelative(documentAnnotation.updatedAt, nowEpochMs)}
            </Text>
            {canAnnotate && (
              <DocumentAnnotationActionMenu
                annotationId={documentAnnotation.id}
                annotationName={documentAnnotation.name}
                spanNodeId={spanNodeId}
                onEdit={() =>
                  onEdit({
                    id: documentAnnotation.id,
                    name: documentAnnotation.name,
                    label: documentAnnotation.label,
                    score: documentAnnotation.score,
                    explanation: documentAnnotation.explanation,
                  })
                }
              />
            )}
          </Flex>
        </Flex>
        {hasDetails && (
          <Flex direction="row" gap="size-200" alignItems="center" wrap="wrap">
            {documentAnnotation.label && (
              <Flex direction="row" gap="size-100" alignItems="center">
                <Text size="XS" color="text-900" weight="heavy">
                  Label
                </Text>
                <Token color={evalTokenColor}>{documentAnnotation.label}</Token>
              </Flex>
            )}
            {typeof documentAnnotation.score === "number" && (
              <Flex direction="row" gap="size-100" alignItems="center">
                <Text size="XS" color="text-900" weight="heavy">
                  Score
                </Text>
                <Token color={evalTokenColor}>
                  {formatFloat(documentAnnotation.score)}
                </Token>
              </Flex>
            )}
            {isAnnotatorKind(documentAnnotation.annotatorKind) && (
              <Flex direction="row" gap="size-100" alignItems="center">
                <Text size="XS" color="text-900" weight="heavy">
                  Kind
                </Text>
                <AnnotatorKindToken kind={documentAnnotation.annotatorKind} />
              </Flex>
            )}
          </Flex>
        )}
        {documentAnnotation.explanation ? (
          <Flex direction="column" gap="size-50">
            <Text size="XS" color="text-900" weight="heavy">
              Explanation
            </Text>
            <Text>{documentAnnotation.explanation}</Text>
          </Flex>
        ) : null}
      </Flex>
    </View>
  );
}
