import React, { useState } from 'react'; import { View } from 'react-native'; import { AlertOctagon, AlertTriangle, Info, ShieldCheck, AlertCircle, Cpu, Layers, Target, Plus, } from 'lucide-react-native'; import type { LucideIcon } from 'lucide-react-native'; import { HeadlineCard, FindingCard, SectionDivider, StatBlock, ChipsRow, Chip, CollapseButton, } from '../editorial'; import type { FindingAccent } from '../../theme/colors'; import type { V3TechniquesResult, TechniqueDefinition } from '../../types/analysis'; import { formatTechniqueName } from '../../utils/formatTechniqueName'; import { localized, useTranslation, smoothEnums } from '../../i18n'; const DEFAULT_VISIBLE = 5; const scoreAccent = (s: number) => s >= 70 ? '#ef4444' : s >= 40 ? '#f97316' : s >= 20 ? '#eab308' : '#22c55e'; const scoreIcon = (s: number): LucideIcon => { if (s >= 70) return AlertOctagon; if (s >= 40) return AlertTriangle; if (s >= 20) return Info; return ShieldCheck; }; const scoreCategory = (s: number, isRo: boolean): string => { if (s >= 70) return isRo ? 'Critic' : 'Critical'; if (s >= 40) return isRo ? 'Ridicat' : 'High'; if (s >= 20) return isRo ? 'Mediu' : 'Medium'; return isRo ? 'Scăzut' : 'Low'; }; const techIcon = (name: string): LucideIcon => { const dim = (name?.split('.')[0] || '').toUpperCase(); if (dim === 'D3') return Cpu; if (dim === 'D5') return Layers; if (dim === 'D8') return Target; return AlertCircle; }; const techAccent = (severity: number): FindingAccent => { if (severity >= 70) return 'critical'; if (severity >= 40) return 'warning'; return 'info'; }; const buildTldr = (r: V3TechniquesResult, isRo: boolean): string => { const techCount = r.techniques_detected?.length ?? 0; const dimCount = r.dimensions_affected?.length ?? 0; const dims = (r.dimensions_affected ?? []).join(' · '); if (techCount === 0) { return isRo ? 'Nicio tehnică de manipulare detectată în acest conținut.' : 'No manipulation techniques detected in this content.'; } return isRo ? `${techCount} ${techCount === 1 ? 'tehnică' : 'tehnici'} de manipulare detectate în ${dimCount} ${dimCount === 1 ? 'dimensiune' : 'dimensiuni'}${dims ? ` (${dims})` : ''}.` : `${techCount} manipulation ${techCount === 1 ? 'technique' : 'techniques'} detected across ${dimCount} ${dimCount === 1 ? 'dimension' : 'dimensions'}${dims ? ` (${dims})` : ''}.`; }; interface Props { result: V3TechniquesResult; defMap?: Map; } export default function TechniquesResults({ result, defMap }: Props) { const { language } = useTranslation(); const isRo = language === 'ro'; const [expanded, setExpanded] = useState(false); const score = result.manipulation_score ?? 0; const accent = scoreAccent(score); const Icon = scoreIcon(score); const techCount = result.techniques_detected?.length ?? 0; const dimCount = result.dimensions_affected?.length ?? 0; const techs = result.techniques_detected ?? []; const visible = expanded ? techs.length : Math.min(DEFAULT_VISIBLE, techs.length); const shown = techs.slice(0, visible); const remaining = techs.length - visible; const warningFlags: string[] = (result.coupling_context as any)?.for_claims?.warning_flags ?? []; return ( 0 ? `${techCount} ${isRo ? (techCount === 1 ? 'tehnică' : 'tehnici') : (techCount === 1 ? 'technique' : 'techniques')} · ${dimCount} ${isRo ? (dimCount === 1 ? 'dimensiune' : 'dimensiuni') : (dimCount === 1 ? 'dimension' : 'dimensions')}` : `${techCount} ${isRo ? (techCount === 1 ? 'tehnică' : 'tehnici') : (techCount === 1 ? 'technique' : 'techniques')}` } tldr={buildTldr(result, isRo)} /> {(score > 0 || dimCount > 0) && ( {(result.dimensions_affected ?? []).map(dim => ( {dim} ))} {techCount > 0 && ( {techCount} {isRo ? 'tehnici detectate' : 'techniques detected'} )} )} {techCount > 0 && ( <> 0 ? ` · ${(result.dimensions_affected ?? []).join(' · ')}` : ''}`} /> {shown.map((tech, i) => { const sev = tech.severity ?? (tech.intensity * 33); const rawName = localized(tech, 'name') || `Technique #${tech.technique_id}`; const def = defMap?.get(rawName); const dimName = localized(tech, 'dimension_name', 'dimension'); const subdimName = localized(tech, 'subdimension_name', 'subdimension'); const eyebrowParts = [ (tech.name?.split('.')[0] || '').toUpperCase() || undefined, dimName ? (subdimName ? `${dimName} · ${subdimName}` : dimName) : undefined, tech.severity != null ? `${isRo ? 'severitate' : 'severity'} ${tech.severity}` : undefined, ].filter(Boolean) as string[]; return ( ); })} {remaining > 0 && ( setExpanded(true)} expanded={false} leading={} label={ isRo ? `Vezi celelalte ${remaining} ${remaining === 1 ? 'tehnică' : 'tehnici'}` : `Show ${remaining} more ${remaining === 1 ? 'technique' : 'techniques'}` } /> )} {expanded && techs.length > DEFAULT_VISIBLE && ( setExpanded(false)} expanded={true} label={isRo ? 'Ascunde' : 'Hide'} /> )} )} {techCount === 0 && ( )} {warningFlags.length > 0 && ( f.replace(/_/g, ' ')).join(' · ')} /> )} ); }