"use client"
import { useState, useRef, useEffect } from "react"
import { Send, Bot, Sparkles, Lock, Loader2, RotateCcw, Copy, Check, Zap } from "lucide-react"
import Link from "next/link"
import type { Plan } from "@/types"
interface Message {
role: "user" | "assistant"
content: string
error?: boolean
}
const SUGGESTED = [
"Which tenants have overdue rent this month?",
"Summarise my open maintenance requests",
"How is my occupancy rate?",
"Which leases are expiring in 60 days?",
"What were my total expenses this quarter?",
"Which property earns the most rent?",
]
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
return (
{
navigator.clipboard.writeText(text).catch(() => {})
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}}
className="flex items-center gap-1 rounded-lg px-2 py-1 text-[10px] text-white/25 hover:text-white/60 hover:bg-white/[0.04] transition"
title="Copy"
>
{copied ? <> Copied> : <> Copy>}
)
}
function MessageBubble({ msg }: { msg: Message }) {
if (msg.role === "user") {
return (
)
}
return (
)
}
interface AiChatProps {
plan: Plan
limit: number
used: number
}
export function AiChat({ plan, limit, used }: AiChatProps) {
const [messages, setMessages] = useState([])
const [input, setInput] = useState("")
const [loading, setLoading] = useState(false)
const [currentUsed, setCurrentUsed] = useState(used)
const bottomRef = useRef(null)
const inputRef = useRef(null)
const isLocked = limit === 0
const isExhausted = !isLocked && currentUsed >= limit
const usagePct = limit > 0 ? Math.min((currentUsed / limit) * 100, 100) : 0
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: "smooth" })
}, [messages, loading])
async function send(question: string) {
if (!question.trim() || loading || isLocked || isExhausted) return
setMessages((prev) => [...prev, { role: "user", content: question }])
setInput("")
setLoading(true)
// Reset textarea height
if (inputRef.current) {
inputRef.current.style.height = "auto"
}
try {
const res = await fetch("/api/ai/ask", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question }),
})
const data = await res.json()
if (!res.ok) {
setMessages((prev) => [...prev, { role: "assistant", content: data.error ?? "Something went wrong.", error: true }])
} else {
setMessages((prev) => [...prev, { role: "assistant", content: data.answer }])
if (data.usage) setCurrentUsed(data.usage.used)
}
} catch {
setMessages((prev) => [...prev, { role: "assistant", content: "Network error. Please try again.", error: true }])
} finally {
setLoading(false)
}
}
function handleKey(e: React.KeyboardEvent) {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault()
send(input)
}
}
return (
{/* Header */}
AI Assistant
Powered by your live portfolio data
{!isLocked && (
{currentUsed} / {limit}
75 ? "bg-amber-500" : "bg-indigo-500"}`}
style={{ width: `${usagePct}%` }}
/>
)}
{messages.length > 0 && (
setMessages([])}
className="flex items-center gap-1.5 rounded-xl border border-white/[0.06] px-3 py-1.5 text-xs text-white/35 hover:text-white hover:border-white/20 transition"
>
Clear
)}
{/* Locked state */}
{isLocked ? (
AI requires Pro plan
Upgrade to unlock AI-powered insights about your properties, tenants, rent collection, and more.
Upgrade to Pro — 50 AI calls/mo
Testing? Switch plan in Demo Data →
) : (
<>
{/* Chat area */}
{messages.length === 0 ? (
How can I help?
I have full access to your live portfolio — properties, tenants, payments, maintenance, and leases.
Try asking
{SUGGESTED.map((q) => (
send(q)}
className="rounded-xl border border-white/[0.06] bg-white/[0.02] px-4 py-3 text-left text-xs text-white/55 hover:border-indigo-500/30 hover:bg-indigo-500/5 hover:text-white/90 transition-all duration-150"
>
{q}
))}
) : (
<>
{messages.map((msg, i) => (
))}
{loading && (
Analysing your portfolio…
)}
>
)}
{/* Input */}
{isExhausted && (
Monthly limit reached. Upgrade for more calls →
)}
Enter to send · Shift+Enter for new line{!isLocked && ` · ${limit - currentUsed} calls left this month`}
>
)}
)
}