import { useState } from "react";
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Search as SearchIcon, Database } from "lucide-react";
import { toast } from "sonner";
import { vault } from "@/lib/vault";
export function Search() {
const [keyword, setKeyword] = useState("");
const [isSearching, setIsSearching] = useState(false);
const [results, setResults] = useState<string[]>([]);
const [hasSearched, setHasSearched] = useState(false);
const [logs, setLogs] = useState<string[]>([]);
const handleSearch = async () => {
if (!keyword) {
toast.error("Please enter a keyword to search");
return;
}
setIsSearching(true);
setHasSearched(false);
setLogs(["[WASM] Generating RO(SE)² keyword trapdoor...", "[WASM] Padding search batch via SWiSSSE protocol..."]);
try {
const stats = await vault.search(keyword);
setLogs(prev => [
...prev,
`[WASM] search() completed in ${stats.time_ms.toFixed(2)}ms`,
`[SWiSSSE] Vol. Hiding: Found ${stats.real_evaluated} matched ciphertexts.`,
`[SWiSSSE] Evaluated and discarded ${stats.dummies_discarded} dummies.`,
"[WASM] Local Authenticated Decryption successful."
]);
setResults(stats.results);
setHasSearched(true);
toast.success("Query Successful", {
description: `Retrieved ${stats.results.length} items from Vault.`,
});
console.log(`[ROSE-SDK] search(${keyword}) ->`, stats.results);
} catch (e) {
toast.error("WASM Search Error", { description: String(e) });
console.error(e);
setLogs(prev => [...prev, `[ERROR] ${String(e)}`]);
} finally {
setIsSearching(false);
}
};
return (
<div className="max-w-4xl mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-3xl font-bold tracking-tight mb-2 text-white">Search Vault</h1>
<p className="text-slate-400">Retrieve documents via encrypted O(1) keyword queries.</p>
</div>
<Card className="border-slate-800 shadow-2xl bg-slate-900/60 backdrop-blur-xl text-slate-100 mb-6 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-purple-500/5 to-pink-500/5 pointer-events-none" />
<CardHeader className="relative z-10">
<CardTitle className="flex items-center text-xl text-white">
<SearchIcon className="mr-2 h-5 w-5 text-purple-400" />
Query Index
</CardTitle>
<CardDescription className="text-slate-400">
Generates a tamper-proof search token locally. The untrusted server evaluates it blindly.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6 relative z-10">
<div className="space-y-2">
<Label htmlFor="keyword" className="text-slate-300">Target Keyword</Label>
<div className="flex gap-3">
<Input
id="keyword"
placeholder="e.g. secret"
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
className="max-w-md bg-slate-950/50 border-slate-700 text-white placeholder:text-slate-600 focus-visible:ring-purple-500"
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
/>
<Button onClick={handleSearch} disabled={isSearching} variant="secondary" className="bg-purple-600/20 text-purple-300 border border-purple-500/30 hover:bg-purple-600/40 hover:text-purple-100">
{isSearching ? "Generating Token..." : "Search"}
</Button>
</div>
</div>
<div className="bg-slate-950/80 p-4 rounded-lg border border-slate-800 text-sm font-mono text-slate-400 flex flex-col space-y-1 shadow-inner max-h-48 overflow-y-auto">
<span className="text-emerald-600 dark:text-emerald-400 font-semibold mb-1">// SWiSSSE Protocol Log</span>
{logs.length === 0 ? (
<span>{'>'} Idle. Awaiting query execution...</span>
) : (
logs.map((log, i) => (
<span key={i} className={isSearching && i === logs.length - 1 ? "text-purple-500 animate-pulse" : ""}>
{'>'} {log}
</span>
))
)}
</div>
</CardContent>
</Card>
{hasSearched && (
<Card className="border-emerald-500/30 shadow-2xl bg-emerald-950/30 backdrop-blur-xl text-slate-100">
<CardHeader>
<CardTitle className="flex items-center text-lg text-emerald-400">
<Database className="mr-2 h-5 w-5" />
Decrypted Results
</CardTitle>
</CardHeader>
<CardContent>
{results.length > 0 ? (
<ul className="space-y-2">
{results.map((r, i) => (
<li key={i} className="px-4 py-3 border border-slate-700/50 rounded-md bg-slate-900/60 flex items-center justify-between shadow-inner">
<span className="font-mono text-slate-300">{r}</span>
<span className="text-xs font-semibold tracking-wider uppercase bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 px-2 py-1 rounded">Decrypted</span>
</li>
))}
</ul>
) : (
<p className="text-slate-400 italic">No documents found matching this encryption search token.</p>
)}
</CardContent>
</Card>
)}
</div>
);
}