'use client';

/**
 * Ticket-scoped phishing campaign review page — the Autotask LiveLink target
 * (REVIEW-01, REVIEW-05, REVIEW-06). Resolves the URL's numeric ticket id to
 * its campaign via a two-step fetch, drives a
 * loading/not-triaged/ungrouped/ready/error state machine, and composes the
 * plan-03/04/05 cards. Authentication is the existing Better Auth session
 * only (this route is not in middleware.ts's publicRoutes) — no separate
 * token/query-param auth scheme.
 */

import { use, useCallback, useEffect, useState } from 'react';
import { SearchX, Sparkles } from 'lucide-react';
import { PageHeader } from '@/components/navigation/page-header';
import { EmptyState } from '@/components/ui/empty-state';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { SkeletonCard, SkeletonHeader } from '@/components/ui/skeleton-helpers';
import { toast } from 'sonner';
import { useSession } from '@/lib/auth-client';
import { hasPermission } from '@/lib/permissions';
import { ClassificationCard, type ClassificationCardData } from '@/components/phishing/classification-card';
import { ActionAreaCard, type RemediationActionSummary } from '@/components/phishing/action-area-card';
import {
  EvidenceCard,
  type EvidenceMessage,
  type BlastRadiusResult,
} from '@/components/phishing/evidence-card';
import { TimelineCard, type TimelineEntry } from '@/components/phishing/timeline-card';

type PageState = 'loading' | 'not-triaged' | 'ungrouped' | 'ready' | 'error';

interface TicketCampaignResolution {
  found: boolean;
  reportId?: string;
  campaignId?: string | null;
  ticketNumber?: string | null;
}

interface CampaignReport {
  id: string;
  ticketId: string;
  ticketNumber: string | null;
  companyName: string | null;
  title: string | null;
  createdAt: string;
  requesterEmail: string | null;
}

interface CampaignMessage {
  id: string;
  reportId: string;
  messageId: string | null;
  subject: string | null;
  headers: EvidenceMessage['headers'];
  urls: EvidenceMessage['urls'];
  attachments: EvidenceMessage['attachments'];
  bodyPreview: string | null;
}

interface CampaignDetail {
  id: string;
  campaignKey: string | null;
  groupMethod: string | null;
  firstSeenAt: string | null;
  lastSeenAt: string | null;
  reportCount: number;
  status: string;
  createdAt: string;
  updatedAt: string;
  reports: CampaignReport[];
  messages: CampaignMessage[];
  classifications: ClassificationCardData[];
  remediationActions: RemediationActionSummary[];
  blastRadius: BlastRadiusResult;
  timeline: TimelineEntry[];
}

interface StandaloneReport {
  id: string;
  ticketId: string;
  ticketNumber: string | null;
  companyName: string | null;
  title: string | null;
  createdAt: string;
  requesterEmail: string | null;
  messages: EvidenceMessage[];
  blastRadius: BlastRadiusResult;
}

/** `open` reads as "Awaiting triage" per UI-SPEC; everything else is a snake_case -> Title Case fallback. */
function humanizeStatus(status: string): string {
  if (status === 'open') return 'Awaiting triage';
  return status
    .split('_')
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    .join(' ');
}

export default function TicketReviewPage({
  params,
}: {
  params: Promise<{ ticketId: string }>;
}) {
  const { ticketId } = use(params);
  const { data: session } = useSession();
  const role = (session?.user as { role?: string } | undefined)?.role ?? 'user';
  const canClassify = hasPermission(role, 'phishing', 'analyze');

  const [state, setState] = useState<PageState>('loading');
  const [resolution, setResolution] = useState<TicketCampaignResolution | null>(null);
  const [campaignId, setCampaignId] = useState<string | null>(null);
  const [campaignDetail, setCampaignDetail] = useState<CampaignDetail | null>(null);
  const [standaloneReport, setStandaloneReport] = useState<StandaloneReport | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [isAnalyzing, setIsAnalyzing] = useState(false);
  const [isClassifying, setIsClassifying] = useState(false);

  const load = useCallback(async () => {
    setState('loading');
    setError(null);
    try {
      const resolveRes = await fetch(`/api/phishing/tickets/${ticketId}/campaign`);
      if (!resolveRes.ok) throw new Error(`Request failed: ${resolveRes.status}`);
      const resolved: TicketCampaignResolution = await resolveRes.json();
      setResolution(resolved);

      if (!resolved.found) {
        setState('not-triaged');
        return;
      }

      if (!resolved.campaignId) {
        // D-08: report exists but grouping hasn't linked it to a campaign yet.
        const reportRes = await fetch(`/api/phishing/reports/${resolved.reportId}`);
        if (!reportRes.ok) throw new Error(`Request failed: ${reportRes.status}`);
        const report: StandaloneReport = await reportRes.json();
        setStandaloneReport(report);
        setCampaignId(null);
        setCampaignDetail(null);
        setState('ungrouped');
        return;
      }

      const detailRes = await fetch(`/api/phishing/campaigns/${resolved.campaignId}`);
      if (!detailRes.ok) throw new Error(`Request failed: ${detailRes.status}`);
      const detail: CampaignDetail = await detailRes.json();
      setCampaignId(resolved.campaignId);
      setCampaignDetail(detail);
      setStandaloneReport(null);
      setState('ready');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error');
      setState('error');
    }
  }, [ticketId]);

  useEffect(() => {
    void load();
  }, [load]);

  async function handleAnalyze() {
    setIsAnalyzing(true);
    try {
      const res = await fetch(`/api/phishing/tickets/${ticketId}/analyze`, { method: 'POST' });
      const data = await res.json();
      if (!res.ok) throw new Error(data.message ?? data.error ?? 'Analyze failed');
      toast.success('Ticket analyzed');
      await load();
    } catch (err) {
      toast.error(`Analyze failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
    } finally {
      setIsAnalyzing(false);
    }
  }

  async function handleClassify() {
    if (!campaignId) return;
    setIsClassifying(true);
    try {
      const res = await fetch(`/api/phishing/campaigns/${campaignId}/classify`, { method: 'POST' });
      const data = await res.json();
      if (!res.ok) throw new Error(data.message ?? data.error ?? 'Classify failed');
      toast.success('Campaign classified');
      await load();
    } catch (err) {
      toast.error(`Classify failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
    } finally {
      setIsClassifying(false);
    }
  }

  const ticketNumberLabel = resolution?.ticketNumber ?? ticketId;
  const description =
    state === 'ready' && campaignDetail
      ? humanizeStatus(campaignDetail.status)
      : state === 'not-triaged'
        ? 'Not yet triaged'
        : state === 'ungrouped'
          ? 'Grouping in progress'
          : undefined;

  return (
    <main className="container mx-auto px-6 py-6 space-y-6">
      <PageHeader
        title={`Ticket #${ticketNumberLabel}`}
        description={description}
        breadcrumbs={[
          { label: 'Phishing', href: '/phishing' },
          { label: `Ticket #${ticketNumberLabel}` },
        ]}
      />

      {state === 'loading' && (
        <div className="space-y-6">
          <SkeletonHeader />
          <SkeletonCard />
          <SkeletonCard />
          <SkeletonCard />
        </div>
      )}

      {state === 'not-triaged' && (
        <EmptyState
          icon={SearchX}
          title="Not yet triaged"
          description="This ticket hasn't been scanned for phishing indicators yet. Run analysis now to extract evidence and see a classification."
          action={{ label: isAnalyzing ? 'Analyzing…' : 'Analyze this ticket', onClick: handleAnalyze }}
        />
      )}

      {state === 'ungrouped' && standaloneReport && (
        <div className="space-y-6">
          <Alert>
            <AlertDescription>
              Grouping in progress — this report hasn&apos;t been linked to a campaign yet. The
              evidence below is from this report only; classification and remediation will appear
              once grouping completes.
            </AlertDescription>
          </Alert>
          <EvidenceCard messages={standaloneReport.messages} blastRadius={standaloneReport.blastRadius} />
        </div>
      )}

      {state === 'error' && (
        <Alert variant="destructive">
          <AlertDescription className="flex items-center justify-between gap-4">
            <span>Couldn&apos;t load this campaign. {error} — try reloading the page.</span>
            <Button variant="outline" size="sm" onClick={() => void load()}>
              Retry
            </Button>
          </AlertDescription>
        </Alert>
      )}

      {state === 'ready' &&
        campaignDetail &&
        campaignId &&
        (() => {
          // Single latest classification (Warning 3): a freshly-grouped
          // campaign returns classifications: [] -> null, the default state
          // since detection/grouping never auto-triggers classification.
          const classification = campaignDetail.classifications[0] ?? null;
          const primaryReport = campaignDetail.reports[0] ?? null;
          const primaryMessage = primaryReport
            ? campaignDetail.messages.find((m) => m.reportId === primaryReport.id) ?? null
            : null;

          const evidenceMessages: EvidenceMessage[] = campaignDetail.messages.map((m) => {
            const report = campaignDetail.reports.find((r) => r.id === m.reportId);
            return {
              id: m.id,
              ticketNumber: report?.ticketNumber ?? null,
              reportCreatedAt: report?.createdAt ?? null,
              headers: m.headers,
              urls: m.urls,
              attachments: m.attachments,
              bodyPreview: m.bodyPreview ?? '',
            };
          });

          const evidence = {
            requesterEmail: primaryReport?.requesterEmail ?? null,
            senderEmail: primaryMessage?.headers.from.email ?? null,
            senderDomain: primaryMessage?.headers.from.domain ?? null,
            messageId: primaryMessage?.messageId ?? null,
          };

          if (classification == null) {
            return (
              <div className="space-y-6">
                <EmptyState
                  icon={Sparkles}
                  title="Not yet classified"
                  description="This campaign is grouped but hasn't been classified yet. Run classification to generate a verdict and recommended remediation actions."
                  action={
                    canClassify
                      ? {
                          label: isClassifying ? 'Classifying…' : 'Classify this campaign',
                          onClick: handleClassify,
                        }
                      : undefined
                  }
                />
                <div className="grid gap-6 lg:grid-cols-2">
                  <EvidenceCard messages={evidenceMessages} blastRadius={campaignDetail.blastRadius} />
                  <TimelineCard timeline={campaignDetail.timeline} />
                </div>
              </div>
            );
          }

          return (
            <div className="space-y-6">
              <ClassificationCard
                campaignId={campaignId}
                classification={classification}
                onReclassified={load}
              />
              <ActionAreaCard
                campaignId={campaignId}
                classification={classification}
                remediationActions={campaignDetail.remediationActions}
                campaignStatus={campaignDetail.status}
                campaignUpdatedAt={campaignDetail.updatedAt}
                evidence={evidence}
                onActionComplete={load}
              />
              <div className="grid gap-6 lg:grid-cols-2">
                <EvidenceCard messages={evidenceMessages} blastRadius={campaignDetail.blastRadius} />
                <TimelineCard timeline={campaignDetail.timeline} />
              </div>
            </div>
          );
        })()}
    </main>
  );
}
