'use client';

/* EvidenceCard — tabbed, read-only rendering of a reported message's parsed
 * EML evidence: Headers, URLs, Attachments, Body preview, Blast Radius
 * (REVIEW-03).
 *
 * This is the phase's biggest XSS-exposure surface: every value rendered
 * here originates from an attacker-controlled email. Body preview is
 * rendered ONLY as JSX text inside a <pre> (React auto-escapes) — never via
 * a raw-HTML injection prop. Extracted URLs are delegated to <UrlList>, which
 * enforces the D-09 inert-copy-only contract. Attachment content is never
 * fetched or rendered — filename/content-type/size/hash metadata only
 * (EVID-04). */

import { useMemo, useState } from 'react';
import { formatDistanceToNow } from 'date-fns';
import { FileText, Copy } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { StatusBadge } from '@/components/ui/status-badge';
import { Button } from '@/components/ui/button';
import { UrlList } from '@/components/phishing/url-list';
import { toast } from 'sonner';

// ── Shapes (from the extended campaign detail route) ──────────────────────

export interface EvidenceMessageHeaders {
  from: { displayName: string | null; email: string | null; domain: string | null };
  replyTo: string | null;
  returnPath: string | null;
  to: string[];
  cc: string[];
  subject: string | null;
  date: string | null;
  messageId: string | null;
  receivedChain: string[];
  authResults: { spf?: string | null; dkim?: string | null; dmarc?: string | null };
  authResultsOriginal?: { spf?: string | null; dkim?: string | null; dmarc?: string | null } | null;
}

export interface EvidenceAttachment {
  filename: string | null;
  contentType: string | null;
  size: number;
  checksum: string | null;
  related: boolean;
}

export interface EvidenceMessage {
  id: string;
  ticketNumber: string | null;
  reportCreatedAt: string | null;
  headers: EvidenceMessageHeaders;
  urls: string[];
  attachments: EvidenceAttachment[];
  bodyPreview: string;
}

export type BlastRadiusResult =
  | { status: 'unavailable'; reason: 'not_configured' | 'lookup_failed'; error?: string }
  | {
      status: 'ok';
      matched: number;
      delivered: number;
      held: number;
      rejected: number;
      clicked: number;
      perRecipient: Array<{ recipient: string; status: 'delivered' | 'held' | 'rejected' | 'unknown' }>;
    };

interface EvidenceCardProps {
  messages: EvidenceMessage[];
  blastRadius: BlastRadiusResult;
}

// ── Small local helpers ─────────────────────────────────────────────────

function formatBytes(bytes: number | null): string {
  if (!bytes) return '0 B';
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let i = 0;
  let val = bytes;
  while (val >= 1024 && i < units.length - 1) {
    val /= 1024;
    i++;
  }
  return `${val.toFixed(1)} ${units[i]}`;
}

function authBadge(value: string | null | undefined) {
  const normalized = (value ?? '').toLowerCase();
  if (normalized === 'pass') {
    return <StatusBadge variantClass="bg-green-500/15 text-green-600">pass</StatusBadge>;
  }
  if (normalized === 'fail') {
    return <StatusBadge variantClass="bg-red-500/15 text-red-600">fail</StatusBadge>;
  }
  return <StatusBadge variantClass="bg-slate-500/15 text-slate-600">{normalized || 'none'}</StatusBadge>;
}

/**
 * Mirrors campaign-classifier.ts's effectiveAuthResults(): the outer
 * Authentication-Results header reflects the reporting/forwarding hop, not
 * the reported message's real delivery — it's near-universally broken for
 * tickets that came through Outlook's Report Message add-in. Prefer the
 * pre-forward authResultsOriginal when captured; only fall back to the
 * outer header when no original was recorded (e.g. a manually-forwarded or
 * KnowBe4 PhishER-sourced ticket).
 */
function effectiveAuthResults(headers: EvidenceMessageHeaders | undefined): {
  result: EvidenceMessageHeaders['authResults'];
  isOriginal: boolean;
} {
  if (!headers) {
    return { result: {}, isOriginal: false };
  }
  if (headers.authResultsOriginal) {
    return { result: headers.authResultsOriginal, isOriginal: true };
  }
  return { result: headers.authResults, isOriginal: false };
}

function recipientStatusBadge(status: string) {
  switch (status) {
    case 'delivered':
      return <StatusBadge variantClass="bg-green-500/15 text-green-600">delivered</StatusBadge>;
    case 'held':
      return <StatusBadge variantClass="bg-amber-500/15 text-amber-600">held</StatusBadge>;
    case 'rejected':
      return <StatusBadge variantClass="bg-destructive/15 text-destructive">rejected</StatusBadge>;
    default:
      return <StatusBadge variantClass="bg-muted text-muted-foreground">unknown</StatusBadge>;
  }
}

async function copyToClipboard(value: string) {
  await navigator.clipboard.writeText(value);
  toast.success('Copied');
}

function unavailableCopy(result: { status: 'unavailable'; reason: 'not_configured' | 'lookup_failed'; error?: string }) {
  if (result.reason === 'not_configured') {
    return "Blast radius unavailable — Mimecast isn't configured for this environment.";
  }
  return `Blast radius lookup failed: ${result.error ?? 'Unknown error'}. Classification proceeded without it.`;
}

// ── Component ───────────────────────────────────────────────────────────

export function EvidenceCard({ messages, blastRadius }: EvidenceCardProps) {
  const [selectedId, setSelectedId] = useState<string | undefined>(messages[0]?.id);

  const message = useMemo(
    () => messages.find((m) => m.id === selectedId) ?? messages[0] ?? null,
    [messages, selectedId],
  );

  const authResults = useMemo(() => effectiveAuthResults(message?.headers), [message]);

  return (
    <Card>
      <CardHeader>
        <CardTitle className="font-bold">
          <FileText className="h-4 w-4 mr-2 inline" />
          Evidence
        </CardTitle>
      </CardHeader>
      <CardContent>
        {messages.length > 1 && (
          <div className="mb-4">
            <Select value={message?.id} onValueChange={setSelectedId}>
              <SelectTrigger className="w-full sm:w-80">
                <SelectValue placeholder="Select a report" />
              </SelectTrigger>
              <SelectContent>
                {messages.map((m) => (
                  <SelectItem key={m.id} value={m.id}>
                    Report: Ticket #{m.ticketNumber ?? '—'}
                    {m.reportCreatedAt
                      ? ` — ${formatDistanceToNow(new Date(m.reportCreatedAt), { addSuffix: true })}`
                      : ''}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        )}

        {!message ? (
          <p className="text-sm text-muted-foreground">No message evidence available.</p>
        ) : (
          <Tabs defaultValue="headers">
            <TabsList>
              <TabsTrigger value="headers">Headers</TabsTrigger>
              <TabsTrigger value="urls">URLs</TabsTrigger>
              <TabsTrigger value="attachments">Attachments</TabsTrigger>
              <TabsTrigger value="body">Body preview</TabsTrigger>
              <TabsTrigger value="blast-radius">Blast Radius</TabsTrigger>
            </TabsList>

            <TabsContent value="headers">
              <div className="grid grid-cols-[8rem_minmax(0,1fr)] gap-x-4 gap-y-2 text-sm">
                <span className="text-muted-foreground">From</span>
                <span className="font-mono text-xs break-all">{message.headers.from.email ?? '—'}</span>

                <span className="text-muted-foreground">Display name</span>
                <span>{message.headers.from.displayName ?? '—'}</span>

                <span className="text-muted-foreground">Sender domain</span>
                <span className="font-mono text-xs break-all">{message.headers.from.domain ?? '—'}</span>

                <span className="text-muted-foreground">Reply-To</span>
                <span className="font-mono text-xs break-all">{message.headers.replyTo ?? '—'}</span>

                <span className="text-muted-foreground">Return-Path</span>
                <span className="font-mono text-xs break-all">{message.headers.returnPath ?? '—'}</span>

                <span className="text-muted-foreground">To</span>
                <span className="font-mono text-xs break-all">{message.headers.to.join(', ') || '—'}</span>

                <span className="text-muted-foreground">Cc</span>
                <span className="font-mono text-xs break-all">{message.headers.cc.join(', ') || '—'}</span>

                <span className="text-muted-foreground">Subject</span>
                <span>{message.headers.subject ?? '—'}</span>

                <span className="text-muted-foreground">Date</span>
                <span className="font-mono text-xs break-all">{message.headers.date ?? '—'}</span>

                <span className="text-muted-foreground">Message-ID</span>
                <span className="font-mono text-xs break-all">{message.headers.messageId ?? '—'}</span>

                <span className="text-muted-foreground">SPF</span>
                <span>{authBadge(authResults.result.spf)}</span>

                <span className="text-muted-foreground">DKIM</span>
                <span>{authBadge(authResults.result.dkim)}</span>

                <span className="text-muted-foreground">DMARC</span>
                <span>{authBadge(authResults.result.dmarc)}</span>

                <span />
                <span className="text-xs text-muted-foreground">
                  {authResults.isOriginal
                    ? 'as verified at original delivery'
                    : 'as received (no pre-forward record)'}
                </span>
              </div>

              {message.headers.receivedChain.length > 0 && (
                <Accordion type="single" collapsible className="mt-4">
                  <AccordionItem value="received-chain">
                    <AccordionTrigger className="text-sm">Received chain</AccordionTrigger>
                    <AccordionContent>
                      <ul className="flex flex-col gap-1">
                        {message.headers.receivedChain.map((hop, index) => (
                          <li key={index} className="font-mono text-xs break-all">
                            {hop}
                          </li>
                        ))}
                      </ul>
                    </AccordionContent>
                  </AccordionItem>
                </Accordion>
              )}
            </TabsContent>

            <TabsContent value="urls">
              <UrlList urls={message.urls} />
            </TabsContent>

            <TabsContent value="attachments">
              {message.attachments.length === 0 ? (
                <p className="text-sm text-muted-foreground">No attachments on this message.</p>
              ) : (
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead>Filename</TableHead>
                      <TableHead>Content-Type</TableHead>
                      <TableHead>Size</TableHead>
                      <TableHead>Hash</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {message.attachments.map((attachment, index) => (
                      <TableRow key={index}>
                        <TableCell className="text-sm">{attachment.filename ?? '—'}</TableCell>
                        <TableCell>
                          <StatusBadge variantClass="bg-slate-500/15 text-slate-600">
                            {attachment.contentType ?? 'unknown'}
                          </StatusBadge>
                        </TableCell>
                        <TableCell className="text-sm">{formatBytes(attachment.size)}</TableCell>
                        <TableCell>
                          {attachment.checksum ? (
                            <div className="flex items-center gap-2">
                              <span
                                className="font-mono text-xs truncate max-w-40"
                                title={attachment.checksum}
                              >
                                {attachment.checksum}
                              </span>
                              <Button
                                size="icon"
                                variant="ghost"
                                aria-label="Copy hash"
                                onClick={() => copyToClipboard(attachment.checksum as string)}
                              >
                                <Copy className="h-3.5 w-3.5" />
                              </Button>
                            </div>
                          ) : (
                            <span className="text-muted-foreground text-xs">—</span>
                          )}
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              )}
            </TabsContent>

            <TabsContent value="body">
              <pre className="max-h-96 overflow-y-auto whitespace-pre-wrap rounded-md bg-muted p-4 font-mono text-xs">
                {message.bodyPreview}
              </pre>
            </TabsContent>

            <TabsContent value="blast-radius">
              {blastRadius.status === 'unavailable' ? (
                <p className="text-sm text-muted-foreground">{unavailableCopy(blastRadius)}</p>
              ) : (
                <div className="flex flex-col gap-4">
                  <div className="grid grid-cols-5 gap-4 text-sm">
                    <div>
                      <div className="text-muted-foreground text-xs">Matched</div>
                      <div className="num">{blastRadius.matched}</div>
                    </div>
                    <div>
                      <div className="text-muted-foreground text-xs">Delivered</div>
                      <div className="num">{blastRadius.delivered}</div>
                    </div>
                    <div>
                      <div className="text-muted-foreground text-xs">Held</div>
                      <div className="num">{blastRadius.held}</div>
                    </div>
                    <div>
                      <div className="text-muted-foreground text-xs">Rejected</div>
                      <div className="num">{blastRadius.rejected}</div>
                    </div>
                    <div>
                      <div className="text-muted-foreground text-xs">Clicked</div>
                      <div className="num">{blastRadius.clicked}</div>
                    </div>
                  </div>
                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead>Recipient</TableHead>
                        <TableHead>Status</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {blastRadius.perRecipient.map((recipient, index) => (
                        <TableRow key={index}>
                          <TableCell className="font-mono text-xs">{recipient.recipient}</TableCell>
                          <TableCell>{recipientStatusBadge(recipient.status)}</TableCell>
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                </div>
              )}
            </TabsContent>
          </Tabs>
        )}
      </CardContent>
    </Card>
  );
}
