import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Bot, Layers, Tag, AlertCircle, ShieldCheck, Zap, ArrowRight,
Activity, FileText, BrainCircuit, LayoutGrid, CheckCircle2,
ImageIcon, ChevronDown, Lightbulb
} from 'lucide-react';
import useTicketStore from "../../store/ticketStore";
import { Card, CardContent } from "../../components/ui/card";
// ─── Shimmer Skeleton ────────────────────────────────────────────────
const Shimmer = ({ className = "" }) => (
);
const SkeletonLoader = () => (
{/* Header skeleton */}
{/* Pipeline skeleton */}
{[1, 2, 3, 4].map(i => (
{i < 4 && }
))}
{/* Summary skeleton */}
{/* Grid skeleton */}
);
// ─── Main Component ──────────────────────────────────────────────────
const AIUnderstanding = () => {
const navigate = useNavigate();
const aiTicket = useTicketStore((state) => state.aiTicket);
const setAITicket = useTicketStore((state) => state.setAITicket);
const [isLoading, setIsLoading] = useState(true);
const [editedIssue, setEditedIssue] = useState("");
const [explainerOpen, setExplainerOpen] = useState(false);
// Simulate a brief load to allow store hydration
useEffect(() => {
const timer = setTimeout(() => setIsLoading(false), 600);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
if (!isLoading && !aiTicket) {
navigate('/create-ticket');
}
}, [isLoading, aiTicket, navigate]);
useEffect(() => {
if (aiTicket?.originalIssue) {
setEditedIssue(aiTicket.originalIssue);
}
}, [aiTicket]);
if (isLoading) return ;
if (!aiTicket) return null;
// ── Dynamic fields from store ──
const summary = aiTicket.summary || aiTicket.originalIssue || "No issue text provided.";
const category = aiTicket.category || "Uncategorized";
const subcategory = aiTicket.subcategory || "None";
const priority = aiTicket.priority || "Medium";
const assignedTeam = aiTicket.assigned_team || "Triage";
const entities = aiTicket.entities || [];
const rawConfidence = aiTicket.confidence;
const confidence = rawConfidence != null ? Math.round(rawConfidence * 100) : 95;
let confBarColor = "bg-red-500";
if (confidence >= 90) confBarColor = "bg-emerald-500";
else if (confidence >= 70) confBarColor = "bg-amber-500";
const priorityLower = (priority || 'medium').toLowerCase();
let priorityColor = "bg-slate-100 text-slate-700";
if (priorityLower === 'high' || priorityLower === 'critical') priorityColor = "bg-red-50 text-red-700";
else if (priorityLower === 'medium') priorityColor = "bg-amber-50 text-amber-700";
else if (priorityLower === 'low') priorityColor = "bg-emerald-50 text-emerald-700";
const handleUpdate = () => {
setAITicket({ ...aiTicket, originalIssue: editedIssue });
};
const handleContinue = () => {
setAITicket({ ...aiTicket, originalIssue: editedIssue, status: 'duplicate_check' });
navigate('/knowledge-check');
};
// ── Pipeline stages ──
const pipelineStages = [
{ label: 'Input', icon: FileText },
{ label: 'AI Analysis', icon: BrainCircuit },
{ label: 'Classification', icon: LayoutGrid },
{ label: 'Decision', icon: CheckCircle2 },
];
const currentStage = aiTicket?.status === 'duplicate_check' ? 2 : (aiTicket?.status === 'analyzing' ? 1 : 0);
// ── Group entities by label ──
const groupedEntities = entities.reduce((acc, entity) => {
const label = entity.label || 'Other';
if (!acc[label]) acc[label] = [];
acc[label].push(entity.text);
return acc;
}, {});
// ── Explainer data ──
const signalTexts = entities.map(e => e.text);
const patternMatch = `${category} > ${subcategory}`;
const safeCategory = String(category || 'General').toLowerCase();
const safeSubcategory = String(subcategory || 'Support').toLowerCase();
const confidenceExplanation = confidence >= 90
? `This issue strongly matches known ${safeCategory} ${safeSubcategory} failures.`
: confidence >= 70
? `This issue partially matches patterns in ${safeCategory} issues.`
: `This issue has a weak match; further review may be needed.`;
return (
{/* 1. Page Header */}
AI Analysis Complete
Our AI analyzed your request and identified the issue.
{/* Horizontal Analysis Pipeline */}
{pipelineStages.map((stage, idx) => {
const Icon = stage.icon;
const isCompleted = idx < currentStage;
const isCurrent = idx === currentStage;
return (
{idx < pipelineStages.length - 1 && (
)}
);
})}
{/* 2. Issue Summary Card */}
{/* 3. AI Classification Card */}
Classification
Category & Subcategory
{category}
/
{subcategory}
Assigned Team
{assignedTeam}
{/* 4. Entities & 5. Confidence */}
{/* Entities Extracted — Grouped by Type */}
Technical Signals Detected
{Object.keys(groupedEntities).length > 0 ? (
{Object.entries(groupedEntities).map(([label, texts]) => (
{label}
{texts.map((t, idx) => (
{t}
))}
))}
) : (
No specific signals detected.
)}
{/* Technical Environment — User visible diagnostic */}
{aiTicket.env_metadata && (
Technical Environment
Interface IP
{aiTicket.env_metadata.ip || '127.0.0.1'}
Device Signal
{aiTicket.env_metadata.user_agent ? aiTicket.env_metadata.user_agent.split(' ').slice(0, 3).join(' ') + '...' : 'SECURE_NODE'}
)}
{/* OCR Screenshot Entities */}
{aiTicket.ocrText && (
Detected from Screenshot
{aiTicket.ocrText.split(/\n|,/).filter(Boolean).map((line, idx) => {
const trimmed = line.trim();
if (!trimmed) return null;
return (
{trimmed}
);
})}
)}
{/* Confidence Meter */}
AI Confidence: {confidence}%
{/* Collapsible: How AI reached this conclusion */}
{/* Signals Detected */}
Signals Detected
{signalTexts.length > 0 ? signalTexts.map((s, idx) => (
{s}
)) : (
No specific signals
)}
{/* Pattern Matched */}
Pattern Matched
{patternMatch}
{/* Confidence Explanation */}
Confidence Explanation
"{confidenceExplanation}"
{/* 6. User Correction Section */}
Is something missing?
{/* 7. Continue Button */}
);
};
export default AIUnderstanding;