import React, { useState, useRef, useEffect } from 'react';
import { MessageSquareText, ClipboardCheck, PenLine, Loader2, Copy, Upload } from 'lucide-react';
import { getToken } from '../services/auth';
import { listDocuments } from '../services/account';
import { useApp } from '../context/AppContext';
import { requestOfferAssistant } from '../services/offerAssistant';
/**
* Teklif Asistanı sekmesi — üç araç (İhaleAB'den taşındı):
* 1) Belgeye Sor: doküman/ilan metninde soru → [n] atıflı yanıt
* 2) Taslağı Denetle: teklif taslağı × gereklilikler → karşılanıyor / eksik / belirsiz
* 3) Taslak Üret: kapak / teknik / ticari / tam dosya (rakam uydurmaz, [DOLDURUN])
* Doküman metni sunucuda EKAP'tan alınır; yoksa buradan .txt/.pdf metni yapıştırılır.
*/
const ORNEKLER = ['Geçici teminat oranı ve süresi nedir?', 'Teslim süresi kaç gün?', 'Gecikme cezası ne kadar?', 'Hangi belgeler istenmiş?', 'Numune isteniyor mu?'];
const DURUM = { karsilaniyor: ['Karşılanıyor', 'bg-emerald-100 text-emerald-800 border-emerald-200'], eksik: ['Eksik', 'bg-red-100 text-red-800 border-red-200'], belirsiz: ['Belirsiz', 'bg-amber-100 text-amber-800 border-amber-200'] };
export const TeklifAsistani = ({ tender }) => {
const {authUser} = useApp();
const token = getToken();
const identity = useRef({token, revision:0});
if (identity.current.token !== token) identity.current = {token, revision:identity.current.revision + 1};
return ;
};
const OfferAssistantSession = ({ tender }) => {
const live = useRef(true);
const session = useRef(getToken());
const busy = useRef(false);
useEffect(() => { live.current = true; return () => { live.current = false; }; }, []);
const current = () => live.current && Boolean(session.current) && getToken() === session.current;
const post = (url, body, documents) => requestOfferAssistant({url, body, readToken:getToken, isCurrent:current, listDocuments:documents});
const [arac, setArac] = useState('sor');
const [metin, setMetin] = useState(''); // isteğe bağlı: yapıştırılan doküman metni
const [sourceName, setSourceName] = useState('');
const [soru, setSoru] = useState('');
const [cevap, setCevap] = useState(null);
const [taslak, setTaslak] = useState('');
const [denetim, setDenetim] = useState(null);
const [tur, setTur] = useState('tam');
const [bolumler, setBolumler] = useState([]);
const [draftReview, setDraftReview] = useState(null);
const [draftSource, setDraftSource] = useState(null);
const [mesgul, setMesgul] = useState(false);
const [hata, setHata] = useState(null);
const calistir = async (fn) => {
if (busy.current || !current()) return;
busy.current = true; setMesgul(true); setHata(null);
try { await fn(); }
catch (e) { if (current()) setHata(e.message); }
finally { busy.current = false; if (current()) setMesgul(false); }
};
const sor = (q) => calistir(async () => {
const result = await post('/api/ai/belge-sor', {ikn:tender.ikn, soru:q, text:metin || undefined, tender});
if (current()) setCevap(result);
});
const denetle = () => calistir(async () => {
const result = await post('/api/ai/teklif-denetim', {ikn:tender.ikn, taslak, tender, text:metin || undefined});
if (current()) setDenetim(result);
});
const uret = () => calistir(async () => {
const result = await post('/api/ai/teklif-taslak', {ikn:tender.ikn, tur, tender, text:metin || undefined}, listDocuments);
if (current()) { setBolumler(result.bolumler || []); setDraftReview(result.draftReview || null); setDraftSource(metin); }
});
const kopyala = (t) => { if (current()) navigator.clipboard?.writeText(t).catch(() => {}); };
const dosyaOku = (f) => {
if (!f) return;
return calistir(async () => {
const { extractText } = await import('../services/pdfText');
if (!current()) return;
const r = await extractText(f);
if (typeof r.text !== 'string' || !r.text.trim()) throw new Error('Dosyada okunabilir metin bulunamadı. Önceki kaynak değiştirilmedi. Başka bir dosya seçin.');
if (current()) { setMetin(r.text); setSourceName(f.name); setCevap(null); setDenetim(null); }
});
};
const Sekme = ({ id, icon: Icon, children }) => (
setArac(id)}
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-bold border ${arac === id ? 'bg-violet-600 text-white border-violet-600' : 'bg-white text-slate-700 border-slate-200 hover:bg-slate-50'}`}>
{children}
);
return (
Belgeye Sor
Taslağı Denetle
Taslak Üret
{metin ? `Kaynak: ${sourceName} (${metin.length.toLocaleString('tr-TR')} kr.)` : 'Doküman yükle (.pdf/.txt) — isteğe bağlı'}
{const file=e.target.files?.[0];e.target.value='';dosyaOku(file);}} />
{metin &&
{setMetin('');setSourceName('');setCevap(null);setDenetim(null);}}>Yüklenen kaynağı kaldır ve ilan kaynağını kullan }
Metin sağlanmazsa sunucu EKAP dokümanını / ilan metnini kullanır. Yanıtların kaynak parçalarını kontrol edin; AI yanıtları hata veya eksik bilgi içerebilir.
{hata &&
{hata}
}
{arac === 'sor' && (
{!cevap &&
{ORNEKLER.map((o) => { setSoru(o); sor(o); }} className="rounded-full border border-slate-200 px-2 py-0.5 text-[11px] text-slate-600 hover:bg-slate-50">{o} )}
}
{cevap && (
{cevap.cevap}
{cevap.kaynaklar?.map((k) => (
[{k.n}] kaynak parça
{k.alinti}
))}
{cevap.kapsam &&
{cevap.kapsam} {cevap.sourceReview && `${cevap.sourceReview.totalChunks} parçadan ${cevap.sourceReview.selectedChunks} tanesi modele sunuldu.`}
}
{cevap.kaynak &&
Kaynak: {cevap.kaynak}
}
)}
)}
{arac === 'denet' && (
)}
{arac === 'uret' && (
setTur(e.target.value)} className="bg-slate-50 border border-slate-200 rounded-lg px-2 py-1.5 text-sm">
Teklif mektubu (kapak) Teknik teklif Ticari teklif Tam dosya
{mesgul ? : } {bolumler.length ? 'Yeniden üret' : 'Taslağı üret'}
{bolumler.length > 0 &&
kopyala(bolumler.map((b) => `${b.baslik}\n\n${b.icerik}`).join('\n\n\n'))} className="text-xs text-slate-600 border border-slate-200 rounded-lg px-2 py-1.5 flex items-center gap-1 hover:bg-slate-50"> Tümünü kopyala }
{bolumler.length > 0 && draftSource !== metin &&
Kaynak değişti. Aşağıdaki taslak önceki kaynakla üretildi; düzenlemeleriniz korundu. Yeni kaynakla karşılaştırın veya yeniden üretin.
}
{draftReview &&
{draftReview.status === 'partial' ? 'Kısmi taslak — bölüm kontrolü gerekli' : 'Taslak — kullanıcı kontrolü gerekli'}
{draftReview.note}
{draftReview.missingSections?.length > 0 &&
Modelin tamamlamadığı bölümler: {draftReview.missingSections.join(', ')}. Aşağıdaki DOLDURUN alanlarını düzenleyin.
}
{draftReview.extraSections?.length > 0 &&
İstenen başlıklara eşleşmeyen ek bölümler: {draftReview.extraSections.join(', ')}.
}
}
{bolumler.map((b, i) => (
setBolumler((p) => p.map((x, k) => (k === i ? { ...x, baslik: e.target.value } : x)))} className="w-full border border-slate-200 rounded-lg px-2 py-1 text-sm font-bold" />
))}
)}
);
};