'use client';

import { useRef, type ReactNode } from 'react';
import { MoreHorizontal, Download, Image as ImageIcon } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { cn } from '@/lib/utils';
import { triggerBlobDownload } from '@/lib/utils/download';

interface ChartCardProps {
  title: string;
  description?: string;
  /** Filename stem used for both CSV + PNG exports (no extension). */
  exportFilename: string;
  /** Returns CSV content for the current chart data, or null when nothing to export. */
  toCsv?: () => string | null;
  children: ReactNode;
  className?: string;
}

async function exportContainerAsPng(container: HTMLElement, filename: string) {
  const svg = container.querySelector('svg');
  if (!svg) return;
  const clone = svg.cloneNode(true) as SVGSVGElement;
  const { width, height } = svg.getBoundingClientRect();
  clone.setAttribute('width', String(width));
  clone.setAttribute('height', String(height));
  clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  const xml = new XMLSerializer().serializeToString(clone);
  const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(xml)}`;
  const img = new Image();
  await new Promise<void>((resolve, reject) => {
    img.onload = () => resolve();
    img.onerror = () => reject(new Error('Failed to load chart for export'));
    img.src = svgDataUrl;
  });
  const canvas = document.createElement('canvas');
  const dpr = window.devicePixelRatio ?? 1;
  canvas.width = width * dpr;
  canvas.height = height * dpr;
  const ctx = canvas.getContext('2d');
  if (!ctx) return;
  ctx.scale(dpr, dpr);
  ctx.fillStyle = '#ffffff';
  ctx.fillRect(0, 0, width, height);
  ctx.drawImage(img, 0, 0, width, height);
  const blob = await new Promise<Blob | null>((resolve) =>
    canvas.toBlob((b) => resolve(b), 'image/png'),
  );
  if (!blob) return;
  triggerBlobDownload(blob, filename);
}

export function ChartCard({
  title,
  description,
  exportFilename,
  toCsv,
  children,
  className,
}: ChartCardProps) {
  const containerRef = useRef<HTMLDivElement>(null);

  function onDownloadCsv() {
    const csv = toCsv?.();
    if (!csv) return;
    triggerBlobDownload(
      new Blob([csv], { type: 'text/csv;charset=utf-8' }),
      `${exportFilename}.csv`,
    );
  }

  function onDownloadPng() {
    if (containerRef.current) {
      void exportContainerAsPng(containerRef.current, `${exportFilename}.png`);
    }
  }

  return (
    <Card className={cn('h-full flex flex-col', className)}>
      <CardHeader className="flex flex-row items-start justify-between gap-2 space-y-0">
        <div>
          <CardTitle className="text-base">{title}</CardTitle>
          {description ? <p className="mt-1 text-xs text-muted-foreground">{description}</p> : null}
        </div>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              variant="ghost"
              size="sm"
              className="h-8 w-8 p-0"
              aria-label="Chart options"
              data-testid="chart-menu"
            >
              <MoreHorizontal className="h-4 w-4" aria-hidden />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end" className="w-44">
            {toCsv ? (
              <DropdownMenuItem onSelect={onDownloadCsv}>
                <Download className="mr-2 h-4 w-4" aria-hidden />
                Download CSV
              </DropdownMenuItem>
            ) : null}
            <DropdownMenuItem onSelect={onDownloadPng}>
              <ImageIcon className="mr-2 h-4 w-4" aria-hidden />
              Download PNG
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </CardHeader>
      <CardContent className="flex-1 flex items-center justify-center">
        <div ref={containerRef} className="w-full">
          {children}
        </div>
      </CardContent>
    </Card>
  );
}
