"use client"
import { useState } from "react"
import Image from "next/image"
import { useRouter } from "next/navigation"
import { AnimatePresence, motion } from "motion/react"
import { useSession } from "@/lib/auth-client"
import type { GameSettingCategory } from "@/lib/db/schema/performanceEntries"
import {
ThumbsUpIcon,
ThumbsDownIcon,
FlagIcon,
TrashIcon,
ChevronLeftIcon,
ChevronRightIcon,
ShieldCheckIcon,
XIcon,
UserIcon,
ShareIcon,
PencilIcon,
} from "lucide-react"
import { TiptapRenderer } from "@/components/tiptap-renderer"
interface Preset {
id: string
gameId?: string
hardwareSlug: string
hardwareName: string
upvotes: number
downvotes: number
settingsJson: GameSettingCategory[] | null
settingsCount: number
fpsAvg: number | null
fpsLow: number | null
fpsHigh: number | null
fpsOnePercentLow: number | null
upscalerType: string | null
upscalerVersion: string | null
frameGenMethod: string | null
protonVersion: string | null
osVersion: string | null
launchOptions: string | null
loadTimeSsd: number | null
loadTimeSd: number | null
tdpWatts: number | null
youtubeVideoId: string | null
screenshots: Array<{ id: string; url: string; width: number; height: number }> | null
hardwareWattHours: number | null
hardwareDeviceType: string | null
customSystem: boolean
userNotes: string | null
userId: string
userName: string | null
userImage: string | null
verifiedAt: string | null
isPinned: boolean
pinnedAt: string | null
createdAt: string
}
interface PresetDetailModalProps {
preset: Preset
gameId: string
onClose: () => void
onDelete: (presetId: string) => void
onReport: (
presetId: string,
reason: "inaccurate" | "spam" | "inappropriate" | "other",
details?: string,
) => void
hasReported: boolean
}
function formatDate(value: string | null): string {
if (!value) return "—"
return new Date(value).toLocaleDateString()
}
function formatValue(value: string | number | boolean): string {
if (typeof value === "boolean") return value ? "On" : "Off"
return String(value)
}
export function PresetDetailModal({
preset,
gameId,
onClose,
onDelete,
onReport,
hasReported,
}: PresetDetailModalProps) {
const router = useRouter()
const { data: session } = useSession()
const [activeCategoryIndex, setActiveCategoryIndex] = useState(0)
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
const [showReportForm, setShowReportForm] = useState(false)
const [reportReason, setReportReason] = useState<
"inaccurate" | "spam" | "inappropriate" | "other"
>("inaccurate")
const [reportDetails, setReportDetails] = useState("")
const [copied, setCopied] = useState(false)
const [userVote, setUserVote] = useState<"up" | "down" | null>(null)
const [localUpvotes, setLocalUpvotes] = useState(preset.upvotes)
const [localDownvotes, setLocalDownvotes] = useState(preset.downvotes)
const [mobileTab, setMobileTab] = useState<"details" | "settings">("settings")
const isOwner = session?.user?.id === preset.userId
const isAdmin = session?.user?.role === "admin"
const isAuthenticated = !!session?.user
const handleShare = () => {
const url = `${window.location.origin}/game/${gameId}?preset=${preset.id}`
navigator.clipboard.writeText(url)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
const categories = preset.settingsJson ?? []
const hasCategories = categories.length > 0
const currentCategory = hasCategories ? categories[activeCategoryIndex] : null
const goPrevCategory = () => {
setActiveCategoryIndex((prev) => (prev > 0 ? prev - 1 : categories.length - 1))
}
const goNextCategory = () => {
setActiveCategoryIndex((prev) => (prev < categories.length - 1 ? prev + 1 : 0))
}
const handleUpvote = async () => {
if (!isAuthenticated || userVote === "up") return
try {
const res = await fetch(`/api/performance/${preset.id}/upvote`, { method: "POST" })
if (res.ok) {
if (userVote === "down") setLocalDownvotes((d) => d - 1)
setLocalUpvotes((u) => u + 1)
setUserVote("up")
}
} catch (err) {
console.error("Failed to upvote:", err)
}
}
const handleDownvote = async () => {
if (!isAuthenticated || userVote === "down") return
try {
const res = await fetch(`/api/performance/${preset.id}/downvote`, { method: "POST" })
if (res.ok) {
if (userVote === "up") setLocalUpvotes((u) => u - 1)
setLocalDownvotes((d) => d + 1)
setUserVote("down")
}
} catch (err) {
console.error("Failed to downvote:", err)
}
}
const handleReportSubmit = () => {
onReport(
preset.id,
reportReason,
reportDetails.trim() || undefined,
)
setShowReportForm(false)
setReportDetails("")
}
const handleTogglePin = async () => {
const method = preset.isPinned ? "DELETE" : "POST"
try {
const res = await fetch(`/api/performance/${preset.id}/pin`, { method })
if (res.ok) {
router.refresh()
}
} catch (err) {
console.error("Failed to toggle pin:", err)
}
}
return (
No settings data
{preset.hardwareName}
{currentCategory?.settings.map((setting, sIdx) => (
Setting
Value
))}
{setting.title}
{formatValue(setting.value)}
Notes