'use client';

import { useState, useEffect } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { format } from 'date-fns';
import { Archive, Download, Edit, FileText, Loader2, Receipt } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ArchiveConfirmDialog } from '@/components/shared/archive-confirm-dialog';
import { PermissionGate } from '@/components/shared/permission-gate';
import { toast } from 'sonner';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import { useMobileChrome } from '@/components/layout/mobile/mobile-layout-provider';
import type { ExpenseRow } from './expense-columns';
import { ExpenseDuplicateBanner } from './expense-duplicate-banner';

/**
 * Renders an image thumbnail for previewable receipts (jpeg/png/webp/heic
 * via the existing /files/[id]/preview presign), falling back to a "Download"
 * link for PDFs and other non-previewable types. Replaces the prior
 * impossible-to-use UUID-badge list - reps can finally see the receipt
 * they uploaded against the expense.
 */
function ReceiptThumbnail({ fileId }: { fileId: string }) {
  const { data, isLoading, isError } = useQuery<{
    data: { url: string; mimeType: string } | null;
    error?: string;
  }>({
    queryKey: ['file-preview', fileId],
    queryFn: async () => {
      try {
        const res = await apiFetch<{ data: { url: string; mimeType: string } }>(
          `/api/v1/files/${fileId}/preview`,
        );
        return res;
      } catch (e) {
        // Non-image files raise ValidationError ("This file type cannot be
        // previewed") - fall through to the Download link.
        return { data: null, error: e instanceof Error ? e.message : 'preview unavailable' };
      }
    },
    staleTime: 5 * 60 * 1000,
  });

  if (isLoading) {
    return (
      <div className="flex h-32 items-center justify-center rounded border bg-muted/40 text-xs text-muted-foreground">
        <Loader2 className="mr-2 h-3 w-3 animate-spin" aria-hidden /> Loading preview…
      </div>
    );
  }

  const url = data?.data?.url;
  const mime = data?.data?.mimeType ?? '';
  const isImage = mime.startsWith('image/');

  return (
    <div className="rounded border bg-muted/40 p-2">
      {url && isImage ? (
        <a href={url} target="_blank" rel="noopener noreferrer">
          <img
            src={url}
            alt="Receipt"
            className="h-32 w-full rounded object-cover hover:opacity-90"
          />
        </a>
      ) : (
        <div className="flex h-32 items-center justify-center text-muted-foreground">
          <FileText className="h-8 w-8" aria-hidden />
        </div>
      )}
      <div className="mt-2 flex items-center justify-between text-xs text-muted-foreground">
        <span className="truncate">{mime || (isError ? 'Receipt' : 'File')}</span>
        <a
          href={`/api/v1/files/${fileId}/download?redirect=1`}
          className="inline-flex items-center gap-1 text-primary hover:underline"
        >
          <Download className="h-3 w-3" aria-hidden /> Download
        </a>
      </div>
    </div>
  );
}

const PAYMENT_STATUS_COLORS: Record<string, string> = {
  unpaid: 'bg-red-100 text-red-700 border-red-200',
  paid: 'bg-green-100 text-green-700 border-green-200',
  partial: 'bg-yellow-100 text-yellow-700 border-yellow-200',
};

interface ExpenseDetailProps {
  expenseId: string;
  onEdit?: () => void;
  onArchived?: () => void;
}

export function ExpenseDetail({ expenseId, onEdit, onArchived }: ExpenseDetailProps) {
  const queryClient = useQueryClient();
  const [archiveOpen, setArchiveOpen] = useState(false);

  const { data, isLoading, error } = useQuery<{ data: ExpenseRow }>({
    queryKey: ['expenses', expenseId],
    queryFn: () => apiFetch(`/api/v1/expenses/${expenseId}`),
  });

  const { setChrome } = useMobileChrome();
  const titleForChrome: string | null =
    data?.data?.establishmentName ?? data?.data?.description?.slice(0, 40) ?? null;
  useEffect(() => {
    setChrome({ title: titleForChrome ?? 'Expense', showBackButton: true });
    return () => setChrome({ title: null, showBackButton: false });
  }, [titleForChrome, setChrome]);

  const archiveMutation = useMutation({
    mutationFn: () => apiFetch(`/api/v1/expenses/${expenseId}`, { method: 'DELETE' }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['expenses'] });
      setArchiveOpen(false);
      toast.success('Expense archived');
      onArchived?.();
    },
    onError: (e) => {
      toastError(e);
      setArchiveOpen(false);
    },
  });

  if (isLoading) {
    return (
      <div className="flex items-center justify-center p-12">
        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" aria-hidden />
      </div>
    );
  }

  if (error || !data?.data) {
    return (
      <div className="p-6 text-center text-muted-foreground">Failed to load expense details.</div>
    );
  }

  const expense = data.data;
  const status = expense.paymentStatus ?? 'unpaid';
  const statusColor = PAYMENT_STATUS_COLORS[status] ?? '';

  return (
    <div className="space-y-6">
      <ExpenseDuplicateBanner expense={expense} />
      <div className="flex items-center justify-between">
        <div>
          <h2 className="text-xl font-semibold">
            {expense.establishmentName ?? 'Unnamed Expense'}
          </h2>
          <p className="text-sm text-muted-foreground mt-0.5">
            {format(new Date(expense.expenseDate), 'MMMM d, yyyy')}
          </p>
        </div>
        <div className="flex items-center gap-2">
          {onEdit && (
            <PermissionGate resource="expenses" action="edit">
              <Button variant="outline" size="sm" onClick={onEdit}>
                <Edit className="mr-1.5 h-4 w-4" aria-hidden />
                Edit
              </Button>
            </PermissionGate>
          )}
          <PermissionGate resource="expenses" action="delete">
            <Button
              variant="outline"
              size="sm"
              className="text-destructive"
              onClick={() => setArchiveOpen(true)}
            >
              <Archive className="mr-1.5 h-4 w-4" aria-hidden />
              Archive
            </Button>
          </PermissionGate>
        </div>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
        <Card>
          <CardHeader>
            <CardTitle className="text-sm font-medium">Amount</CardTitle>
          </CardHeader>
          <CardContent>
            <p className="text-2xl font-bold tabular-nums">
              {Number(expense.amount).toLocaleString(undefined, {
                minimumFractionDigits: 2,
                maximumFractionDigits: 2,
              })}{' '}
              {expense.currency}
            </p>
            {expense.amountUsd && expense.currency !== 'USD' && (
              <p className="text-sm text-muted-foreground mt-1">
                ≈ $
                {Number(expense.amountUsd).toLocaleString(undefined, {
                  minimumFractionDigits: 2,
                  maximumFractionDigits: 2,
                })}{' '}
                USD
              </p>
            )}
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-sm font-medium">Payment Status</CardTitle>
          </CardHeader>
          <CardContent>
            <Badge variant="outline" className={`capitalize text-sm border ${statusColor}`}>
              {status}
            </Badge>
          </CardContent>
        </Card>
      </div>

      <Card>
        <CardHeader>
          <CardTitle className="text-sm font-medium">Details</CardTitle>
        </CardHeader>
        <CardContent className="grid grid-cols-2 gap-4 text-sm">
          <div>
            <span className="text-muted-foreground">Category</span>
            <p className="mt-0.5 capitalize">{expense.category?.replace(/_/g, ' ') ?? '-'}</p>
          </div>
          <div>
            <span className="text-muted-foreground">Payment Method</span>
            <p className="mt-0.5 capitalize">{expense.paymentMethod?.replace(/_/g, ' ') ?? '-'}</p>
          </div>
          <div>
            <span className="text-muted-foreground">Payer</span>
            <p className="mt-0.5">{expense.payer ?? '-'}</p>
          </div>
          <div>
            <span className="text-muted-foreground">Trip / event</span>
            <p className="mt-0.5">
              {expense.tripLabel ? (
                <Badge variant="secondary" className="text-xs font-normal">
                  {expense.tripLabel}
                </Badge>
              ) : (
                '-'
              )}
            </p>
          </div>
          <div>
            <span className="text-muted-foreground">Description</span>
            <p className="mt-0.5">{expense.description ?? '-'}</p>
          </div>
        </CardContent>
      </Card>

      {expense.receiptFileIds && expense.receiptFileIds.length > 0 && (
        <Card>
          <CardHeader>
            <CardTitle className="text-sm font-medium flex items-center gap-2">
              <Receipt className="h-4 w-4" aria-hidden />
              Receipts ({expense.receiptFileIds.length})
            </CardTitle>
          </CardHeader>
          <CardContent>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
              {(expense.receiptFileIds as string[]).map((fileId) => (
                <ReceiptThumbnail key={fileId} fileId={fileId} />
              ))}
            </div>
          </CardContent>
        </Card>
      )}

      <ArchiveConfirmDialog
        open={archiveOpen}
        onOpenChange={setArchiveOpen}
        entityName={expense.establishmentName ?? 'this expense'}
        entityType="Expense"
        isArchived={false}
        onConfirm={() => archiveMutation.mutate()}
        isLoading={archiveMutation.isPending}
      />
    </div>
  );
}
