'use client';

import { useEffect, useMemo, useState } from 'react';
import { AlertTriangle, ChevronLeft, ChevronRight, Trash2 } from 'lucide-react';

import DetectionLocationMap from '@/components/map/detectionLocationMap';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import AnnotatedDetectionImage from '@/components/video/annotatedDetectionImage';
import { getDefectVisual } from '@/constants/defectVisualConfig';
import { cn } from '@/lib/utils';

import {
  useDiscardDetectionMutation,
  useTicketDetectionsQuery,
} from '../../hooks/useTicketQueries';
import { DetectionDiscardDialog } from './DetectionDiscardDialog';

interface TicketDetectionPreviewProps {
  ticketId: string;
  videoId?: string | null;
  assignmentId?: number;
  assignmentStatus?: 'unassigned';
  onDetectionCountChange?: (count: number | undefined) => void;
}

function DetectionMetadataBar({
  items,
}: {
  items: { label: string; value: string | number }[];
}) {
  return (
    <div className="rounded-lg bg-muted/40 px-4 py-4">
      <div className="grid grid-cols-1 gap-4 sm:grid-cols-3 sm:divide-x sm:divide-border/70">
        {items.map((item, index) => (
          <div
            key={item.label}
            className={cn(
              'space-y-1',
              index === 0 && 'sm:pr-4',
              index === 1 && 'sm:px-4',
              index === 2 && 'sm:pl-4',
            )}
          >
            <p className="text-xs text-muted-foreground">{item.label}</p>
            <div className="text-sm font-semibold text-foreground">
              {item.value}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function TicketDetectionPreviewSkeleton() {
  return (
    <>
      <div className="grid grid-cols-1 gap-4 xl:grid-cols-2">
        <div className="min-w-0 space-y-2">
          <Skeleton className="h-3 w-24" />
          <Skeleton className="aspect-video w-full rounded-lg" />
        </div>
        <div className="min-w-0 space-y-2">
          <Skeleton className="h-3 w-28" />
          <Skeleton
            className="w-full rounded-lg"
            style={{ aspectRatio: '16 / 9' }}
          />
        </div>
      </div>

      <div className="rounded-lg bg-muted/40 px-4 py-4">
        <div className="grid grid-cols-1 gap-4 sm:grid-cols-3 sm:divide-x sm:divide-border/70">
          {Array.from({ length: 3 }).map((_, index) => (
            <div
              key={index}
              className={cn(
                'space-y-1',
                index === 0 && 'sm:pr-4',
                index === 1 && 'sm:px-4',
                index === 2 && 'sm:pl-4',
              )}
            >
              <Skeleton className="h-3 w-16" />
              <Skeleton className="h-4 w-20" />
            </div>
          ))}
        </div>
      </div>
    </>
  );
}

export function TicketDetectionPreview({
  ticketId,
  videoId,
  assignmentId,
  assignmentStatus,
  onDetectionCountChange,
}: TicketDetectionPreviewProps) {
  const [currentIndex, setCurrentIndex] = useState(0);
  const [isDiscardDialogOpen, setIsDiscardDialogOpen] = useState(false);
  const isUnassignedPreview = assignmentStatus === 'unassigned';

  useEffect(() => {
    setCurrentIndex(0);
  }, [assignmentId, assignmentStatus, videoId]);

  const queryParams = useMemo(
    () => ({
      skip: currentIndex,
      limit: 1,
      assignment_id: isUnassignedPreview ? undefined : assignmentId,
      assignment_status: isUnassignedPreview
        ? ('unassigned' as const)
        : undefined,
      sort: 'timestamp_asc',
    }),
    [assignmentId, currentIndex, isUnassignedPreview],
  );

  const detectionsQuery = useTicketDetectionsQuery(
    videoId ?? undefined,
    queryParams,
  );
  const detectionResult = detectionsQuery.data;
  const activeDetection = detectionResult?.items[0];
  const confirmedDetectionCount = detectionResult?.total;
  const detectionCount = confirmedDetectionCount ?? 0;
  const activeVisual = getDefectVisual(
    activeDetection?.detection.class_name ?? '',
  );
  const ActiveIssueIcon = activeVisual.icon;
  const activeDisplayName =
    activeDetection?.detection.display_name ?? 'Detection';
  const discardMutation = useDiscardDetectionMutation(
    ticketId,
    videoId ?? undefined,
  );

  useEffect(() => {
    if (confirmedDetectionCount === undefined) return;

    if (confirmedDetectionCount === 0 && currentIndex !== 0) {
      setCurrentIndex(0);
      return;
    }

    if (
      confirmedDetectionCount > 0 &&
      currentIndex > confirmedDetectionCount - 1
    ) {
      setCurrentIndex(confirmedDetectionCount - 1);
    }
  }, [confirmedDetectionCount, currentIndex]);

  useEffect(() => {
    onDetectionCountChange?.(confirmedDetectionCount);
  }, [confirmedDetectionCount, onDetectionCountChange]);

  const isNavigationDisabled =
    detectionCount === 0 || detectionsQuery.isLoading;
  const isInitialLoading = detectionsQuery.isLoading;
  const isError = detectionsQuery.isError;
  const retry = () => void detectionsQuery.refetch();

  return (
    <div className="space-y-4">
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex min-w-0 items-center gap-3">
          <span
            className={cn(
              'flex size-10 shrink-0 self-start items-center justify-center rounded-lg',
              activeVisual.cardClassName,
            )}
          >
            <ActiveIssueIcon
              className={cn('size-5', activeVisual.colorClassName)}
            />
          </span>
          <div className="min-w-0">
            <h3>{activeDisplayName}</h3>
          </div>
        </div>

        <div className="flex items-center gap-2 self-start sm:self-auto">
          <Button
            type="button"
            variant="secondary"
            onClick={() =>
              setCurrentIndex((index) =>
                detectionCount === 0
                  ? 0
                  : (index - 1 + detectionCount) % detectionCount,
              )
            }
            disabled={isNavigationDisabled}
            aria-label="Previous detection"
          >
            <ChevronLeft className="size-4" />
          </Button>
          <div className="min-w-16 text-center text-sm font-medium text-foreground">
            {detectionCount === 0
              ? '0 of 0'
              : `${currentIndex + 1} of ${detectionCount}`}
          </div>
          <Button
            type="button"
            variant="secondary"
            onClick={() =>
              setCurrentIndex((index) =>
                detectionCount === 0 ? 0 : (index + 1) % detectionCount,
              )
            }
            disabled={isNavigationDisabled}
            aria-label="Next detection"
          >
            <ChevronRight className="size-4" />
          </Button>
        </div>
      </div>

      {isInitialLoading && !activeDetection ? (
        <TicketDetectionPreviewSkeleton />
      ) : isError ? (
        <div className="rounded-lg border border-dashed border-destructive/40 bg-destructive/5 px-4 py-8 text-center">
          <div className="flex flex-col items-center gap-2">
            <AlertTriangle className="size-6 text-destructive" />
            <p className="text-sm font-medium text-destructive">
              Failed to load detection preview.
            </p>
            <Button type="button" variant="outline" size="sm" onClick={retry}>
              Retry
            </Button>
          </div>
        </div>
      ) : !activeDetection || !detectionResult ? (
        <div className="rounded-lg border border-dashed bg-muted/20 px-4 py-10 text-center text-sm text-muted-foreground">
          {detectionCount > 0
            ? 'The selected detection details are unavailable. Try refreshing the preview.'
            : isUnassignedPreview
              ? 'No unassigned issues remain on this ticket.'
              : 'No detections are available for this issue.'}
        </div>
      ) : (
        <>
          <div className="grid grid-cols-1 items-start gap-4 xl:grid-cols-2">
            <div className="min-w-0 space-y-2">
              <p className="text-muted-foreground">Detection Image</p>
              <div className="w-full overflow-hidden rounded-lg">
                <AnnotatedDetectionImage
                  detection={activeDetection}
                  videoWidth={detectionResult.video_width}
                  videoHeight={detectionResult.video_height}
                  aspectRatio="16 / 9"
                  enableLightbox
                />
              </div>
            </div>

            <DetectionLocationMap
              className="min-w-0"
              latitude={activeDetection.location.latitude}
              longitude={activeDetection.location.longitude}
              label={`${activeDetection.detection.display_name} - Frame ${activeDetection.frame.number}`}
              title="Location on Map"
              variant="plain"
              aspectRatio="16 / 9"
              showCoordinates={false}
            />
          </div>

          <DetectionMetadataBar
            items={[
              {
                label: 'Confidence',
                value: `${Math.round(activeDetection.detection.confidence * 100)}%`,
              },
              {
                label: 'Frame',
                value: activeDetection.frame.number,
              },
              {
                label: 'Timestamp',
                value: `${activeDetection.frame.timestamp_seconds}s`,
              },
            ]}
          />

          {isUnassignedPreview ? (
            <>
              <div className="flex justify-end">
                <Button
                  type="button"
                  variant="destructive"
                  onClick={() => setIsDiscardDialogOpen(true)}
                >
                  <Trash2 />
                  Discard detection
                </Button>
              </div>

              <DetectionDiscardDialog
                open={isDiscardDialogOpen}
                detectionLabel={activeDetection.detection.display_name}
                isPending={discardMutation.isPending}
                onOpenChange={setIsDiscardDialogOpen}
                onSubmit={async (payload) => {
                  await discardMutation.mutateAsync({
                    detectionId: activeDetection.detection.id,
                    payload,
                  });
                  setIsDiscardDialogOpen(false);
                }}
              />
            </>
          ) : null}
        </>
      )}
    </div>
  );
}
