/**
 * DAİ Mail Asistanı — server.js
 * Gmail + Gemini tabanlı iş birliği mail asistanı.
 * Çalıştır: node server.js  →  http://localhost:3737
 *
 * Bağımlılıklar üst klasördeki node_modules'tan gelir (express, googleapis).
 * OAuth token mevcut gmail_bot kurulumuyla paylaşılır.
 */

const express = require('express');
const fs = require('fs');
const os = require('os');
const path = require('path');
const http = require('http');
const https = require('https');
const { spawn } = require('child_process');
const { google } = require('googleapis');
const { verifyData } = require('./lib/license');

const SURUM = '1.2.1'; // uygulama sürümü — her yayında artır

const PORT = Number(process.env.PORT) || 3737;
// SEA / pkg paketlenmişse data/ exe'nin yanında (yazılabilir); kaynak ve arayüz exe içinde gömülü.
let _sea = null; try { _sea = require('node:sea'); } catch {}
const SEA = !!(_sea && _sea.isSea && _sea.isSea());
const TABAN = (process.pkg || SEA) ? path.dirname(process.execPath) : __dirname;
const DATA_DIR = process.env.DAYI_DATA || path.join(TABAN, 'data');
fs.mkdirSync(DATA_DIR, { recursive: true });
function arayuzOku(ad) {
  if (SEA) return _sea.getAsset(ad, 'utf8');
  return fs.readFileSync(path.join(__dirname, 'public', ad), 'utf8');
}
const CONFIG_PATH = path.join(DATA_DIR, 'config.json');
let cfg = null;
try { cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8').replace(/^﻿/, '')); } catch { cfg = null; }

// Kurulum yapılmışsa kullanıcının kendi config'i; yoksa geliştirici (Burak) varsayılanları.
const ESKI_TOKEN = path.join(os.homedir(), '.config', 'gmail_bot', 'token.json');
const TOKEN_PATH = cfg ? path.join(DATA_DIR, 'gmail_token.json') : ESKI_TOKEN;
const STYLE_PATH = cfg ? path.join(DATA_DIR, 'style_profile.json')
                       : path.join(os.homedir(), '.config', 'gmail_bot', 'style_profile.json');
const CREDENTIALS_PATH = path.join(__dirname, '..', 'gmail_credentials.json'); // eski kurulum yedeği
const DB_PATH = path.join(DATA_DIR, 'db.json');
const MEMORY_PATH = path.join(DATA_DIR, 'memory.json');
const CRM_PATH = path.join(DATA_DIR, 'crm.json');
const ISLER_PATH = path.join(DATA_DIR, 'isler.json');

// Birden çok anahtar: kota PROJE bazlıdır, farklı projelerin anahtarları ayrı kota getirir.
const VARSAYILAN_KEYS = [
  'AIzaSyChj1CqEw85iFW7Ku5MHGvSoeOZDbwRHHQ',
  'AIzaSyASr5I-We2x4hPLUY3hzpZLpmMdvObHASw',
  'AIzaSyAbh5p2dkLIXFyj2YDEHQ3056NOsgug0oM',
  'AIzaSyABjSpcGOFcS66T4SDr2MIr2BRlP23nAl8',
];
let GEMINI_KEYS = (
  process.env.GEMINI_API_KEYS ? process.env.GEMINI_API_KEYS.split(',')
  : (cfg && Array.isArray(cfg.geminiKeys) && cfg.geminiKeys.length) ? cfg.geminiKeys
  : VARSAYILAN_KEYS
).map(s => String(s).trim()).filter(Boolean);
function maskeAnahtar(k) { k = String(k || ''); return k.length > 12 ? k.slice(0, 6) + '…' + k.slice(-4) : '••••'; }
// Kota dolunca sıradaki anahtar/modele otomatik geçilir (her model+proje kotası ayrı)
const MODEL_ZINCIRI = (process.env.GEMINI_MODELS || (cfg && cfg.geminiModels) ||
  'gemini-3-flash-preview,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-flash-latest,gemini-flash-lite-latest'
).split(',').map(s => s.trim());

const KATEGORILER = [
  'yeni_isbirligi', 'teklif_bekleyen', 'gorusme', 'icerik_uretim',
  'odeme_bekleyen', 'tamamlanan', 'spam_dolandirici', 'diger',
];

// ─── Depolama ────────────────────────────────────────────────────────────────
fs.mkdirSync(DATA_DIR, { recursive: true });

function loadJson(p, fallback) {
  try { return JSON.parse(fs.readFileSync(p, 'utf8').replace(/^﻿/, '')); } catch { return fallback; }
}
function saveJson(p, obj) {
  fs.writeFileSync(p, JSON.stringify(obj, null, 2), 'utf8');
}

let db = loadJson(DB_PATH, { emails: {}, lastSync: null });
// Tek seferlik onarım: önbellekte HTML kalmış gövdeleri temizle (eski ham çeviri önbelleğini de düşür)
for (const e of Object.values(db.emails || {})) {
  if (htmlGibi(e.body)) {
    e.body = stripHtml(e.body).slice(0, 6000);
    delete e.threadCeviri;
  }
}
if (!db.sozlesmeler) db.sozlesmeler = {};
if (!db.icgoruler) db.icgoruler = null;
let crm = loadJson(CRM_PATH, { markalar: {} });
let isler = loadJson(ISLER_PATH, { liste: [] });
function saveCrm() { saveJson(CRM_PATH, crm); }
function saveIsler() { saveJson(ISLER_PATH, isler); }
function markaKey(ad) { return (ad || '').toLowerCase().trim().replace(/\s+/g, '_'); }
// Eksik alanları varsayılanlarla tamamla. (Kurulum sihirbazı memory'ye sadece profil
// yazıyor; bu yüzden fiyatlar/kategoriler gibi alanlar eksik kalabilir → .map() patlardı.)
let memory = loadJson(MEMORY_PATH, {}) || {};
const VARSAYILAN_MEMORY = {
  fiyatlar: [
    { ad: 'Instagram Reel', fiyat: 3000 },
    { ad: 'YouTube Video (8-12 dk)', fiyat: 6000 },
    { ad: 'YouTube Shorts (1 adet)', fiyat: 800 },
    { ad: 'Story (1 adet)', fiyat: 250 },
  ],
  donusSuresi: '2 gün',
  odemeYontemi: 'Wise',
  sevilenKategoriler: ['AI Araçları', 'Teknoloji', 'Gadget', 'Mobil Oyun', 'Fintech'],
  sevilmeyenKategoriler: ['Bahis', 'Kumar', 'Multi Level Marketing'],
  notlar: [],
  sablonlar: [
    { ad: 'Fiyat Listesi', metin: 'Merhaba,\n\nİlginiz için teşekkürler! Güncel fiyatlarım:\n• Instagram Reel: $3.000\n• YouTube Video: $6.000\n• Story: $250\n\nDetayları konuşmak isterseniz buradayım.\n\nSevgiler,\nTasarımcı Dayı' },
    { ad: 'Kibar Red', metin: 'Merhaba,\n\nTeklifiniz için teşekkür ederim. Maalesef şu anki içerik planıma uymuyor, ama ileride uygun bir fırsat olursa memnuniyetle değerlendiririm.\n\nBaşarılar dilerim,\nTasarımcı Dayı' },
    { ad: 'Brief İste', metin: 'Merhaba,\n\nİş birliğine açığım! Değerlendirebilmem için şu detayları paylaşabilir misiniz:\n• Bütçe aralığı\n• İstenen içerik ve adet\n• Teslim tarihi\n• Kullanım hakları süresi\n\nTeşekkürler,\nTasarımcı Dayı' },
  ],
  faturaBilgileri: {
    unvan: '', adres: '', vergiNo: '', iban: '', wise: '',
    not: 'Ödeme, fatura tarihinden itibaren 30 gün içinde yapılır.',
  },
  menuAyarlari: {
    kategoriler: ['tumu', 'yeni_isbirligi', 'teklif_bekleyen', 'gorusme', 'icerik_uretim', 'odeme_bekleyen', 'tamamlanan', 'spam_dolandirici', 'diger'],
    araclar: ['mail', 'crm', 'gelir', 'takvim', 'sozlesme'],
    adlar: {},   // { key: 'Özel Ad' }
    gizli: [],   // gizlenen menü key'leri
  },
  // Eklentiler: her biri opsiyonel; aktif edilince ilgili özellik panelde görünür/çalışır.
  // hesapGerekli olanlar (whatsapp vb.) ek bilgi ile kurulur; ayar config burada saklanır.
  eklentiler: {
    kazancHedefi: { aktif: false, ayar: { aylikHedef: 10000 } },
    karaListe: { aktif: false, ayar: { markalar: [] } },
    sesliAsistan: { aktif: false },
    icerikPlani: { aktif: false },
    raporKarti: { aktif: false },
    outreach: { aktif: false },
    briefUygunluk: { aktif: false },
  },
};
let _memDuzeldi = false;
for (const [k, v] of Object.entries(VARSAYILAN_MEMORY)) {
  if (memory[k] === undefined || memory[k] === null) { memory[k] = v; _memDuzeldi = true; }
}
// Dizi olması gereken alanlar bozuk gelirse onar
for (const k of ['fiyatlar', 'sevilenKategoriler', 'sevilmeyenKategoriler', 'notlar']) {
  if (!Array.isArray(memory[k])) { memory[k] = VARSAYILAN_MEMORY[k]; _memDuzeldi = true; }
}
if (_memDuzeldi) saveJson(MEMORY_PATH, memory);
if (!memory.profil) {
  memory.profil = {
    ad: 'Tasarımcı Dayı',
    unvan: 'YouTuber · Instagrammer',
    alt: '1.2M Abone · @tasarimcidayi',
    avatar: '', // data-url veya http url
  };
  saveJson(MEMORY_PATH, memory);
}
if (!memory.mediaKit) {
  memory.mediaKit = {
    platformlar: [
      { ad: 'YouTube', takipci: '', ortIzlenme: '', etkilesim: '', notlar: '' },
      { ad: 'Instagram', takipci: '', ortIzlenme: '', etkilesim: '', notlar: '' },
      { ad: 'TikTok', takipci: '', ortIzlenme: '', etkilesim: '', notlar: '' },
    ],
    gorseller: [], // { ad, data: dataURL }
  };
  saveJson(MEMORY_PATH, memory);
}

// Kullanıcının kimliği — profil ayarlarından çekilir (her kullanıcı kendi adıyla imzalar).
function kullaniciAd() { return (memory.profil?.ad || 'Kullanıcı').trim(); }
function kullaniciTanim() {
  const p = memory.profil || {};
  const ek = [p.unvan, p.alt].map(s => (s || '').trim()).filter(Boolean).join(', ');
  return ek ? `${kullaniciAd()} (${ek})` : kullaniciAd();
}

function mediaKitOzet() {
  const p = (memory.mediaKit?.platformlar || []).filter(x => x.takipci || x.ortIzlenme || x.etkilesim);
  if (!p.length) return '';
  return p.map(x => `${x.ad}: ${[
    x.takipci && x.takipci + ' takipçi',
    x.ortIzlenme && 'ort. izlenme ' + x.ortIzlenme,
    x.etkilesim && 'etkileşim ' + x.etkilesim,
    x.notlar,
  ].filter(Boolean).join(', ')}`).join(' | ');
}
const styleProfile = loadJson(STYLE_PATH, {});

let dbDirty = false;
function markDirty() { dbDirty = true; }
setInterval(() => { if (dbDirty) { saveJson(DB_PATH, db); dbDirty = false; } }, 2000);

// ─── Gemini ──────────────────────────────────────────────────────────────────
function geminiCagri(promptOrParts, model, key, { json = false, maxTokens = 4096 } = {}) {
  const parts = Array.isArray(promptOrParts) ? promptOrParts : [{ text: promptOrParts }];
  return new Promise((resolve, reject) => {
    const body = JSON.stringify({
      contents: [{ parts }],
      generationConfig: {
        maxOutputTokens: maxTokens,
        temperature: 0.5,
        // thinking yanıtı ciddi yavaşlatıyor: 2.5'te kapat, gemini-3'te düşük seviyeye çek
        ...(model.startsWith('gemini-2.5') ? { thinkingConfig: { thinkingBudget: 0 } } : {}),
        ...(model.startsWith('gemini-3') && g3ThinkingDestek ? { thinkingConfig: { thinkingLevel: 'low' } } : {}),
        ...(json ? { responseMimeType: 'application/json' } : {}),
      },
    });
    const req = https.request({
      hostname: 'generativelanguage.googleapis.com',
      path: `/v1beta/models/${model}:generateContent?key=${key}`,
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
    }, r => {
      const chunks = [];
      r.on('data', c => chunks.push(c));
      r.on('end', () => {
        try {
          const d = JSON.parse(Buffer.concat(chunks).toString());
          if (d.error) return reject(new Error(d.error.message));
          resolve(d?.candidates?.[0]?.content?.parts?.[0]?.text?.trim() || '');
        } catch (e) { reject(e); }
      });
    });
    req.on('error', reject);
    req.setTimeout(90000, () => { req.destroy(new Error('Gemini zaman aşımı')); });
    req.write(body);
    req.end();
  });
}

// Anahtar×model kombinasyon havuzu: kota dolan kombo soğumaya alınır, sıradakine geçilir.
// Sıralama: önce kaliteli model tüm anahtarlarla, sonra sıradaki model.
// Tüm istekler tek kuyruktan 2 sn aralıkla gider (anahtar başına ~20 istek/dk limiti korunur).
const komboKota = {}; // `${model}|${key}` -> bu zamana kadar kullanma (ms)
let g3ThinkingDestek = true; // gemini-3 thinkingLevel'i reddederse otomatik kapanır
let sonIstekZamani = 0;
let geminiKuyrugu = Promise.resolve();

function uygunKombo() {
  const simdi = Date.now();
  for (const m of MODEL_ZINCIRI) {
    for (const k of GEMINI_KEYS) {
      if (!(komboKota[m + '|' + k] > simdi)) return { model: m, key: k };
    }
  }
  return null;
}

function gemini(promptOrParts, opts = {}) {
  const toplamKombo = MODEL_ZINCIRI.length * GEMINI_KEYS.length;
  const is = geminiKuyrugu.then(async () => {
    const bosluk = sonIstekZamani + 2000 - Date.now();
    if (bosluk > 0) await new Promise(r => setTimeout(r, bosluk));

    for (let deneme = 0; deneme <= toplamKombo; deneme++) {
      let kombo = uygunKombo();
      if (!kombo) {
        // hepsi soğumada: en erken açılanı bekle (en fazla 45 sn)
        const enErken = Math.min(...Object.values(komboKota));
        await new Promise(r => setTimeout(r, Math.min(Math.max(enErken - Date.now(), 1000), 45000)));
        kombo = uygunKombo() || { model: MODEL_ZINCIRI[0], key: GEMINI_KEYS[0] };
      }
      sonIstekZamani = Date.now();
      try {
        return await geminiCagri(promptOrParts, kombo.model, kombo.key, opts);
      } catch (e) {
        // gemini-3 thinkingLevel alanını tanımıyorsa kalıcı kapat ve aynı komboyla tekrar dene
        if (g3ThinkingDestek && kombo.model.startsWith('gemini-3') && /INVALID_ARGUMENT|Unknown name|thinking/i.test(e.message)) {
          g3ThinkingDestek = false;
          console.log('gemini-3 thinkingLevel desteklenmiyor → kapatıldı');
          continue;
        }
        if (/quota|exceeded|RESOURCE_EXHAUSTED|rate limit|high demand|overloaded/i.test(e.message)) {
          // model yoğunluğu (high demand) kısa sürer; kota hatasında Google'ın verdiği süreyi kullan
          const yogunluk = /high demand|overloaded/i.test(e.message);
          const saniye = yogunluk ? 25 : (Number((e.message.match(/retry in ([\d.]+)\s*s/i) || [])[1]) || 60);
          komboKota[kombo.model + '|' + kombo.key] = Date.now() + Math.min(saniye + 5, 120) * 1000;
          console.log(`${kombo.model} + anahtar#${GEMINI_KEYS.indexOf(kombo.key) + 1} ${yogunluk ? 'yoğun' : 'dolu'} (~${Math.round(saniye)}s) → sıradaki`);
          continue;
        }
        throw e;
      }
    }
    throw new Error('Tüm Gemini anahtar/model kotaları dolu — 1-2 dakika sonra tekrar dene');
  });
  geminiKuyrugu = is.catch(() => {});
  return is;
}

async function geminiJson(prompt, opts = {}) {
  let sonHata;
  for (let deneme = 0; deneme < 3; deneme++) {
    try {
      const text = await gemini(prompt, { ...opts, json: true });
      // responseMimeType json olsa da bazen ```json sarmalı gelebilir
      const cleaned = text.replace(/^```json\s*/i, '').replace(/```\s*$/, '');
      return JSON.parse(cleaned);
    } catch (e) {
      sonHata = e;
      await new Promise(r => setTimeout(r, 3000 * (deneme + 1)));
    }
  }
  throw sonHata;
}

// ─── Google Çeviri (ücretsiz gtx ucu — anında, kotasız) ──────────────────────
function googleCevirParca(text) {
  return new Promise((resolve, reject) => {
    const body = 'q=' + encodeURIComponent(text);
    const req = https.request({
      hostname: 'translate.googleapis.com',
      path: '/translate_a/single?client=gtx&sl=auto&tl=tr&dt=t',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        'User-Agent': 'Mozilla/5.0',
      },
    }, r => {
      const chunks = [];
      r.on('data', c => chunks.push(c));
      r.on('end', () => {
        try {
          const d = JSON.parse(Buffer.concat(chunks).toString());
          resolve((d[0] || []).map(seg => seg[0]).join(''));
        } catch (e) { reject(new Error('Çeviri yanıtı çözümlenemedi')); }
      });
    });
    req.on('error', reject);
    req.setTimeout(15000, () => req.destroy(new Error('Çeviri zaman aşımı')));
    req.write(body);
    req.end();
  });
}

async function googleCevir(text) {
  if (!text || !text.trim()) return text;
  // uzun metni paragraf sınırından ~3000 karakterlik parçalara böl
  const parcalar = [];
  let kalan = text;
  while (kalan.length > 3000) {
    let kes = kalan.lastIndexOf('\n', 3000);
    if (kes < 500) kes = 3000;
    parcalar.push(kalan.slice(0, kes));
    kalan = kalan.slice(kes);
  }
  parcalar.push(kalan);
  const sonuc = [];
  for (const p of parcalar) sonuc.push(p.trim() ? await googleCevirParca(p) : p);
  return sonuc.join('');
}

// ─── Gmail ───────────────────────────────────────────────────────────────────
function getAuth() {
  let client_id, client_secret;
  if (cfg && cfg.oauth && cfg.oauth.client_id) {
    ({ client_id, client_secret } = cfg.oauth); // kurulumdan gelen bilgiler
  } else if (fs.existsSync(CREDENTIALS_PATH)) {
    const creds = JSON.parse(fs.readFileSync(CREDENTIALS_PATH));
    ({ client_id, client_secret } = creds.installed || creds.web);
  } else {
    throw new Error('OAuth bilgisi yok — kurulumu tamamlayın.');
  }
  if (!fs.existsSync(TOKEN_PATH)) throw new Error('OAuth token bulunamadı — kurulumu tamamlayın.');
  const client = new google.auth.OAuth2(client_id, client_secret, 'http://localhost:3333/oauth2callback');
  client.setCredentials(JSON.parse(fs.readFileSync(TOKEN_PATH)));
  client.on('tokens', tokens => {
    const current = loadJson(TOKEN_PATH, {});
    saveJson(TOKEN_PATH, { ...current, ...tokens });
  });
  return client;
}

const gmail = google.gmail({ version: 'v1', auth: getAuth() });

function getHeader(headers, name) {
  return headers?.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
}

function decodeBody(payload, prefer = 'text/plain') {
  if (!payload) return '';
  if (payload.mimeType === prefer && payload.body?.data) {
    return Buffer.from(payload.body.data, 'base64').toString('utf8');
  }
  if (payload.parts) {
    for (const p of payload.parts) {
      const t = decodeBody(p, prefer);
      if (t) return t;
    }
  }
  if (!payload.parts && payload.body?.data) {
    return Buffer.from(payload.body.data, 'base64').toString('utf8');
  }
  return '';
}

function stripHtml(html) {
  return html
    .replace(/<style[\s\S]*?<\/style>/gi, ' ')
    .replace(/<script[\s\S]*?<\/script>/gi, ' ')
    .replace(/<head[\s\S]*?<\/head>/gi, ' ')
    .replace(/<!--[\s\S]*?-->/g, ' ')
    .replace(/<br\s*\/?>/gi, '\n')
    .replace(/<\/(p|div|tr|li|h[1-6]|table|blockquote)>/gi, '\n')
    .replace(/<[^>]+>/g, ' ')
    .replace(/&nbsp;/gi, ' ').replace(/&amp;/gi, '&').replace(/&lt;/gi, '<').replace(/&gt;/gi, '>')
    .replace(/&quot;/gi, '"').replace(/&#0?39;|&apos;/gi, "'")
    .replace(/&#(\d+);/g, (_, n) => { try { return String.fromCodePoint(Number(n)); } catch { return ' '; } })
    .replace(/[ \t]+/g, ' ')
    .replace(/ ?\n ?/g, '\n')
    .replace(/\n{3,}/g, '\n\n')
    .trim();
}

// Metin HTML mi içeriyor? (pazarlama araçları text/plain'e bile HTML gömebiliyor)
function htmlGibi(text) {
  return !!text && (text.match(/<[a-z!/][^>]*>/gi) || []).length >= 3;
}

function extractBody(payload) {
  let text = decodeBody(payload, 'text/plain');
  if (!text) {
    const html = decodeBody(payload, 'text/html');
    if (html) text = stripHtml(html);
  } else if (htmlGibi(text)) {
    text = stripHtml(text);
  }
  return (text || '').slice(0, 6000);
}

// Mail gövdesinden alıntılanmış eski yazışmayı ayıkla ("> ...", "On ... wrote:" vb.)
function alintiAyikla(text) {
  if (!text) return { ana: '', alinti: '' };
  const lines = text.split(/\r?\n/);
  let kesim = -1;
  for (let i = 0; i < lines.length; i++) {
    const l = lines[i].trim();
    if (
      /^>/.test(l) ||
      /^On .{5,120} wrote:?\s*$/.test(l) ||
      /^-{3,}\s*(Original Message|Forwarded message)\s*-{3,}/i.test(l) ||
      /tarihinde\s.*\syazd[ıi]:?\s*$/i.test(l) ||
      (/^From:\s/i.test(l) && i + 1 < lines.length && /^(Date|Sent|To|Subject):\s/i.test(lines[i + 1].trim()))
    ) { kesim = i; break; }
  }
  if (kesim === -1) return { ana: text.trim(), alinti: '' };
  return { ana: lines.slice(0, kesim).join('\n').trim(), alinti: lines.slice(kesim).join('\n').trim() };
}

function listAttachments(payload, out = []) {
  if (!payload) return out;
  if (payload.filename && payload.body?.attachmentId) {
    out.push({ name: payload.filename, mimeType: payload.mimeType });
  }
  (payload.parts || []).forEach(p => listAttachments(p, out));
  return out;
}

// ─── Senkronizasyon ──────────────────────────────────────────────────────────
let syncing = false;
let lastSyncError = null;

async function syncEmails() {
  if (syncing) return;
  syncing = true;
  lastSyncError = null;
  try {
    const res = await gmail.users.messages.list({
      userId: 'me', q: 'in:inbox newer_than:45d', maxResults: 60,
    });
    const ids = (res.data.messages || []).map(m => m.id);
    const newIds = ids.filter(id => !db.emails[id]);

    for (const id of newIds) {
      try {
        const r = await gmail.users.messages.get({ userId: 'me', id, format: 'full' });
        const msg = r.data;
        const headers = msg.payload?.headers || [];
        const fromRaw = getHeader(headers, 'From');
        const m = fromRaw.match(/^(?:"?([^"<]*)"?\s*)?<?([^<>\s]+@[^<>\s]+)>?$/);
        db.emails[id] = {
          id,
          threadId: msg.threadId,
          from: (m?.[1] || '').trim() || (m?.[2] || fromRaw),
          fromEmail: m?.[2] || fromRaw,
          subject: getHeader(headers, 'Subject'),
          messageIdHeader: getHeader(headers, 'Message-ID'),
          date: Number(msg.internalDate) || Date.now(),
          snippet: msg.snippet || '',
          body: extractBody(msg.payload),
          attachments: listAttachments(msg.payload),
          unread: (msg.labelIds || []).includes('UNREAD'),
          starred: (msg.labelIds || []).includes('STARRED'),
          kategori: null,
          marka: null,
          risk: null,
          analiz: null,
          cevapTaslagi: null,
          arsivlendi: false,
        };
        markDirty();
      } catch (e) {
        console.error('Mail çekilemedi:', id, e.message);
      }
    }

    // Var olanların okunma/yıldız durumunu güncelle, gelen kutusundan çıkanları işaretle
    const inboxSet = new Set(ids);
    for (const id of Object.keys(db.emails)) {
      if (!inboxSet.has(id)) db.emails[id].arsivlendi = true;
    }

    // Sınıflandırılmamışları Gemini'ye toplu gönder
    const unclassified = Object.values(db.emails).filter(e => !e.kategori);
    for (let i = 0; i < unclassified.length; i += 12) {
      const batch = unclassified.slice(i, i + 12);
      await classifyBatch(batch);
    }

    db.lastSync = Date.now();
    markDirty();
    updateCrm();
    await estimateEarnings();
    onAnaliz(); // arka planda: iş birliği maillerini önceden analiz et
  } catch (e) {
    lastSyncError = e.message;
    console.error('Senkron hatası:', e.message);
  } finally {
    syncing = false;
  }
}

async function classifyBatch(batch) {
  const items = batch.map(e => ({
    id: e.id, kimden: e.from, email: e.fromEmail, konu: e.subject, ozet: e.snippet,
    icerik: (e.body || '').slice(0, 800),
  }));
  const prompt = `Sen ${kullaniciTanim()}'nın mail asistanısın.
Aşağıdaki mailleri sınıflandır. Her mail için JSON dön.

Kategoriler:
- yeni_isbirligi: Yeni gelen sponsorluk/iş birliği teklifi (henüz yanıtlanmamış görünen)
- teklif_bekleyen: Marka fiyat teklifi bekliyor veya fiyat konuşuluyor
- gorusme: Aktif görüşme/pazarlık aşamasında olan iş birliği yazışması
- icerik_uretim: Anlaşma yapılmış, içerik üretim/brief/revizyon aşamasında
- odeme_bekleyen: Fatura/ödeme ile ilgili
- tamamlanan: Tamamlanmış iş, teşekkür, kapanış maili
- spam_dolandirici: Dolandırıcılık, sahte teklif, şüpheli mail (hediye karşılığı bedava iş isteyenler, bahis/kumar, sahte marka mailleri)
- diger: İş birliğiyle ilgisi olmayan her şey (bildirimler, faturalar, kişisel)

risk: "dusuk" | "orta" | "yuksek" (dolandırıcılık ihtimali; ücretsiz alan adından yazan "büyük markalara" dikkat)
marka: Marka/şirket adı (yoksa null)
onem: 1-5 (iş fırsatı değeri)

Mailler:
${JSON.stringify(items, null, 1)}

SADECE şu formatta JSON dizisi dön:
[{"id":"...","kategori":"...","marka":"...","risk":"...","onem":3}]`;

  try {
    const results = await geminiJson(prompt, { maxTokens: 8192 });
    for (const r of results) {
      const e = db.emails[r.id];
      if (!e) continue;
      e.kategori = KATEGORILER.includes(r.kategori) ? r.kategori : 'diger';
      e.marka = r.marka || null;
      e.risk = r.risk || 'dusuk';
      e.onem = r.onem || 1;
    }
    markDirty();
  } catch (e) {
    console.error('Sınıflandırma hatası:', e.message);
  }
}

// ─── Mail analizi (detay paneli) ─────────────────────────────────────────────
async function analyzeEmail(email) {
  const kayit = crm.markalar[markaKey(email.marka)];
  const crmNotu = kayit && kayit.puan
    ? `\nCRM GEÇMİŞİ: Bu markayla daha önce çalışıldı, ${kullaniciAd()} ${kayit.puan}/5 puan verdi${kayit.etiketler?.length ? ' (' + kayit.etiketler.join(', ') + ')' : ''}${kayit.notlar ? '. Not: ' + kayit.notlar : ''}. Bunu teklif skorunda ve cevapta dikkate al, puan düşükse uyar.`
    : '';
  // Gerçek iş geçmişi (isler.json) — AI "geçen sefer $X anlaşmıştın" diyebilsin
  const markaIsleri = isler.liste.filter(i => markaKey(i.marka) === markaKey(email.marka) && i.durum !== 'reddedildi' && i.tutar);
  const gecmisNotu = markaIsleri.length
    ? `\nGERÇEK İŞ GEÇMİŞİ (bu markayla önceki anlaşmalar): ${markaIsleri.map(i => `${i.baslik} $${i.tutar}`).join(', ')}. Ortalama anlaşma: $${Math.round(markaIsleri.reduce((s, i) => s + Number(i.tutar), 0) / markaIsleri.length)}. teklifOzeti.gecmis alanına bunu yansıt ve yeni teklifte tutarlı ol.`
    : '';
  const karaListe = memory.eklentiler?.karaListe?.ayar?.markalar || [];
  const karaListeNotu = karaListe.includes(markaKey(email.marka))
    ? `\n🚫 KARA LİSTE: Bu marka kullanıcı tarafından DOLANDIRICI/SORUNLU olarak işaretlenmiş! Risk skorunu YÜKSEK yap, teklif skorunu düşür, tavsiyeyi "Reddet" yönünde ver ve gerekçede kara listede olduğunu belirt.`
    : '';
  const prompt = `Sen ${kullaniciTanim()}'nın mail asistanısın.${crmNotu}${gecmisNotu}${karaListeNotu}

GÜNCEL FİYAT LİSTESİ (Dayı Hafızası):
${memory.fiyatlar.map(f => `- ${f.ad}: $${f.fiyat}`).join('\n')}
Ödeme yöntemi: ${memory.odemeYontemi} | Ortalama dönüş: ${memory.donusSuresi}
${mediaKitOzet() ? 'KANAL İSTATİSTİKLERİ: ' + mediaKitOzet() : ''}
Sevdiği kategoriler: ${memory.sevilenKategoriler.join(', ')}
Çalışmadığı kategoriler: ${memory.sevilmeyenKategoriler.join(', ')}
${memory.notlar.length ? 'Notlar: ' + memory.notlar.map(n => n.text).join(' | ') : ''}

BURAK'IN YAZIM STİLİ: ${JSON.stringify(styleProfile)}

GELEN MAİL:
Kimden: ${email.from} <${email.fromEmail}>
Konu: ${email.subject}
İçerik:
${email.body || email.snippet}

Bu maili analiz et ve SADECE şu JSON'u dön:
{
 "teklifOzeti": {
   "marka": "...", "urun": "...",
   "istenenIcerik": ["1 Instagram Reel", "..."],
   "butce": "Belirtilmemiş veya $X",
   "teslimTarihi": "... veya Belirtilmemiş",
   "risk": "dusuk|orta|yuksek",
   "gecmis": "Daha önce çalışılmadı / bilinmiyor"
 },
 "degerlendirme": {
   "kalemler": [{"ad": "Instagram Reel", "fiyat": 3000}],
   "toplam": 3500,
   "gerekce": "Fiyat listesine göre kısa gerekçe"
 },
 "markaAnalizi": {
   "website": "...", "sektor": "...", "merkez": "...", "kurulus": "...",
   "calisanSayisi": "...", "sonHaber": "...", "guvenilirlik": "kısa değerlendirme",
   "scamRiski": "Düşük Risk|Orta Risk|Yüksek Risk"
 },
 "teklifSkoru": {
   "puan": 0-100 arası toplam skor,
   "detay": {"markaKalitesi": 0-20, "butceUygunlugu": 0-20, "kanalUyumu": 0-20, "guvenilirlik": 0-20, "uzunDonemPotansiyel": 0-20},
   "yorum": "1 cümlelik gerekçe"
 },
 "tavsiye": {
   "karar": "Kabul Et | Pazarlık Yap | Daha Fazla Bilgi İste | Reddet",
   "gerekce": "1-2 cümle: neden bu karar; iş yükü, ücret, marka itibarı ve uzun dönem potansiyelini tart"
 },
 "gonderimSaati": "Gönderenin muhtemel saat dilimine göre cevabın en uygun gönderim zamanı, TR saatiyle. Örn: 'Gönderen ABD Batı Kıyısı'nda görünüyor; en uygun: TR 18:00-20:00'. Belirsizse 'TR mesai saatleri uygun' yaz.",
 "onerilenCevap": "Kullanıcının stiline uygun, mailin dilinde (TR mail ise TR, EN ise EN) hazır cevap metni. Fiyatları net madde madde yaz. İmza: mail dilinde uygun kapanış + ${kullaniciAd()}."
}

Mail iş birliği teklifi DEĞİLSE degerlendirme.kalemler boş dizi, toplam 0 olsun ve onerilenCevap maile uygun normal bir yanıt olsun. Marka hakkında emin olmadığın bilgilere "bilinmiyor" yaz, uydurma.`;

  const analiz = await geminiJson(prompt, { maxTokens: 8192 });
  email.analiz = analiz;
  email.cevapTaslagi = analiz.onerilenCevap || '';
  // Türkçe karşılık Gemini yerine anlık Google Çeviri'den
  try { email.cevapTurkce = await googleCevir(email.cevapTaslagi); } catch { email.cevapTurkce = ''; }
  markDirty();
  return analiz;
}

// ─── Cevap üretimi (ton/aksiyon) ─────────────────────────────────────────────
async function generateReply(email, { ton = 'Profesyonel', aksiyon = 'teklif', revize = '', mevcutTaslak = '' } = {}) {
  const aksiyonAciklama = {
    teklif: 'Fiyat teklifini net şekilde ilet, iş birliğine sıcak bak.',
    pazarlik: 'Bütçeleri düşükse veya pazarlık gerekiyorsa karşı teklif yap, değerini vurgula.',
    bilgi: 'Teklifi değerlendirmek için eksik detayları (bütçe, brief, tarih, kullanım hakları) sor.',
    reddet: 'Kibarca reddet, kapıyı tamamen kapatma.',
    toplanti: 'Kısa bir görüşme/toplantı öner, müsait zaman dilimleri iste.',
  };
  const gorev = revize
    ? `Aşağıdaki MEVCUT TASLAĞI, kullanıcının revize talimatına göre yeniden yaz. Taslağın dilini ve genel yapısını koru, sadece talimat doğrultusunda değiştir.

MEVCUT TASLAK:
${mevcutTaslak || email.cevapTaslagi || ''}

REVİZE TALİMATI: ${revize}`
    : `GÖREV: ${aksiyonAciklama[aksiyon] || aksiyonAciklama.teklif}
TON: ${ton}`;

  const prompt = `Sen ${kullaniciTanim()}'nın mail asistanısın.

FİYAT LİSTESİ: ${memory.fiyatlar.map(f => `${f.ad}: $${f.fiyat}`).join(' | ')}
Ödeme: ${memory.odemeYontemi} | Dönüş süresi: ${memory.donusSuresi}
${mediaKitOzet() ? 'KANAL İSTATİSTİKLERİ (marka isterse bunları kullan, uydurma): ' + mediaKitOzet() : ''}
YAZIM STİLİ: ${JSON.stringify(styleProfile)}

GELEN MAİL (Kimden: ${email.from}, Konu: ${email.subject}):
${(email.body || email.snippet).slice(0, 4000)}

${gorev}

Mailin dilinde (TR ise TR, EN ise EN) hazır cevap yaz. SADECE mail gövdesini dön, başka hiçbir açıklama ekleme. İmza: uygun kapanış + ${kullaniciAd()}.`;

  const text = (await gemini(prompt, { maxTokens: 2048 })).trim();
  email.cevapTaslagi = text;
  try { email.cevapTurkce = await googleCevir(text); } catch { email.cevapTurkce = ''; }
  markDirty();
  return { text, turkce: email.cevapTurkce };
}

// ─── Mail gönderme ───────────────────────────────────────────────────────────
function encodeSubject(s) {
  return /[^\x20-\x7E]/.test(s) ? `=?UTF-8?B?${Buffer.from(s, 'utf8').toString('base64')}?=` : s;
}

async function buildRaw(email, bodyText, ekler = []) {
  const profile = await gmail.users.getProfile({ userId: 'me' });
  const me = profile.data.emailAddress;
  const subject = email.subject.toLowerCase().startsWith('re:') ? email.subject : `Re: ${email.subject}`;
  const ustBaslik = [
    `From: ${me}`,
    `To: ${email.fromEmail}`,
    `Subject: ${encodeSubject(subject)}`,
    email.messageIdHeader ? `In-Reply-To: ${email.messageIdHeader}` : null,
    email.messageIdHeader ? `References: ${email.messageIdHeader}` : null,
    'MIME-Version: 1.0',
  ].filter(l => l !== null);

  let lines;
  if (!ekler.length) {
    lines = [
      ...ustBaslik,
      'Content-Type: text/plain; charset=UTF-8',
      'Content-Transfer-Encoding: base64',
      '',
      Buffer.from(bodyText, 'utf8').toString('base64'),
    ];
  } else {
    const sinir = 'dayi_' + Math.random().toString(36).slice(2);
    lines = [
      ...ustBaslik,
      `Content-Type: multipart/mixed; boundary="${sinir}"`,
      '',
      `--${sinir}`,
      'Content-Type: text/plain; charset=UTF-8',
      'Content-Transfer-Encoding: base64',
      '',
      Buffer.from(bodyText, 'utf8').toString('base64'),
    ];
    for (const g of ekler) {
      const m = (g.data || '').match(/^data:([^;]+);base64,(.+)$/s);
      if (!m) continue;
      const ad = (g.ad || 'istatistik.png').replace(/[^\w.\-]/g, '_');
      lines.push(
        `--${sinir}`,
        `Content-Type: ${m[1]}; name="${ad}"`,
        `Content-Disposition: attachment; filename="${ad}"`,
        'Content-Transfer-Encoding: base64',
        '',
        m[2],
      );
    }
    lines.push(`--${sinir}--`);
  }
  return Buffer.from(lines.join('\r\n'), 'utf8').toString('base64url');
}

async function sendReply(email, bodyText, ekler = []) {
  const raw = await buildRaw(email, bodyText, ekler);
  const res = await gmail.users.messages.send({
    userId: 'me',
    requestBody: { raw, threadId: email.threadId },
  });
  return res.data;
}

async function saveDraft(email, bodyText) {
  const raw = await buildRaw(email, bodyText);
  const res = await gmail.users.drafts.create({
    userId: 'me',
    requestBody: { message: { raw, threadId: email.threadId } },
  });
  return res.data;
}

// ─── Bu ay olası kazanç tahmini ──────────────────────────────────────────────
async function estimateEarnings() {
  const aktif = Object.values(db.emails).filter(e =>
    !e.arsivlendi && ['yeni_isbirligi', 'teklif_bekleyen', 'gorusme', 'icerik_uretim'].includes(e.kategori));
  if (!aktif.length) {
    db.kazancTahmini = { toplam: 0, aciklama: 'Aktif iş birliği yok', at: Date.now() };
    markDirty();
    return db.kazancTahmini;
  }
  const liste = aktif.map(e => ({
    marka: e.marka, kategori: e.kategori, konu: e.subject, ozet: e.snippet.slice(0, 200),
    analizEdilenTeklif: e.analiz?.degerlendirme?.toplam || null,
    risk: e.risk,
  }));
  const prompt = `Sen ${kullaniciTanim()}'nın mail asistanısın. Bu ay sonuna kadar olası kazancını tahmin et.

FİYAT LİSTESİ: ${memory.fiyatlar.map(f => `${f.ad}: $${f.fiyat}`).join(' | ')}

AKTİF İŞ BİRLİKLERİ (kategori anlamları — yeni_isbirligi: henüz yanıtlanmadı ~%20 olasılık, teklif_bekleyen: fiyat iletildi ~%40, gorusme: pazarlıkta ~%60, icerik_uretim: anlaşıldı ~%95):
${JSON.stringify(liste, null, 1)}

Her iş için: analizEdilenTeklif varsa onu, yoksa fiyat listesinden makul bir tahmini tutar kullan, kapanma olasılığıyla çarp. Yüksek riskli (scam ihtimali) olanları sayma. Toplamı USD olarak ver.

SADECE şu JSON'u dön:
{"toplam": 12500, "aciklama": "1-2 cümle: kaç aktif iş var, tahmin neye dayanıyor"}`;
  try {
    const r = await geminiJson(prompt, { maxTokens: 4096 });
    db.kazancTahmini = { toplam: Math.round(Number(r.toplam) || 0), aciklama: r.aciklama || '', at: Date.now() };
    markDirty();
  } catch (e) {
    console.error('Kazanç tahmini hatası:', e.message);
  }
  return db.kazancTahmini;
}

// ─── Arka plan ön-analizi ────────────────────────────────────────────────────
// Aktif iş birliği maillerini kullanıcı tıklamadan önce analiz eder → detay anında açılır.
let onAnalizCalisiyor = false;
async function onAnaliz() {
  if (onAnalizCalisiyor) return;
  onAnalizCalisiyor = true;
  try {
    const adaylar = Object.values(db.emails)
      .filter(e => !e.arsivlendi && !e.analiz &&
        ['yeni_isbirligi', 'teklif_bekleyen', 'gorusme', 'icerik_uretim'].includes(e.kategori))
      .sort((a, b) => b.date - a.date)
      .slice(0, 6); // döngü başına en yeni 6 mail — kotayı boğmadan
    for (const e of adaylar) {
      try { await analyzeEmail(e); console.log('Ön-analiz tamam:', e.marka || e.from); }
      catch (err) { console.error('Ön-analiz hatası:', e.marka, err.message); break; }
    }
  } finally { onAnalizCalisiyor = false; }
}

// ─── Marka CRM ───────────────────────────────────────────────────────────────
const COLLAB_KATEGORILER = ['yeni_isbirligi', 'teklif_bekleyen', 'gorusme', 'icerik_uretim', 'odeme_bekleyen', 'tamamlanan'];

function updateCrm() {
  for (const e of Object.values(db.emails)) {
    if (!e.marka || !COLLAB_KATEGORILER.includes(e.kategori)) continue;
    const key = markaKey(e.marka);
    if (!key) continue;
    if (!crm.markalar[key]) {
      crm.markalar[key] = { ad: e.marka, puan: null, etiketler: [], notlar: '', benzerMarkalar: null };
    }
  }
  saveCrm();
}

// Türetilmiş alanlar her seferinde maillerden hesaplanır (kullanıcı alanları korunur)
function crmVerisi() {
  const sonuc = {};
  for (const [key, kayit] of Object.entries(crm.markalar)) {
    const mailler = Object.values(db.emails)
      .filter(e => markaKey(e.marka) === key)
      .sort((a, b) => a.date - b.date);
    const kisiler = {};
    for (const e of mailler) {
      if (!kisiler[e.fromEmail]) kisiler[e.fromEmail] = { ad: e.from, email: e.fromEmail, mailSayisi: 0, sonMail: 0, tarihler: [] };
      const k = kisiler[e.fromEmail];
      k.mailSayisi++;
      k.sonMail = Math.max(k.sonMail, e.date);
      k.tarihler.push(e.date);
    }
    // kişi başına ortalama dönüş aralığı (ardışık mailleri arası, gün)
    for (const k of Object.values(kisiler)) {
      const t = k.tarihler.sort((a, b) => a - b);
      let toplam = 0, n = 0;
      for (let i = 1; i < t.length; i++) { toplam += t[i] - t[i - 1]; n++; }
      k.ortDonusGun = n ? +(toplam / n / 86400000).toFixed(1) : null;
      delete k.tarihler;
    }
    const markaIsler = isler.liste.filter(i => markaKey(i.marka) === key);
    sonuc[key] = {
      ...kayit,
      key,
      mailSayisi: mailler.length,
      sonGorusme: mailler.length ? mailler[mailler.length - 1].date : null,
      sonKonu: mailler.length ? mailler[mailler.length - 1].subject : null,
      kisiler: Object.values(kisiler),
      isSayisi: markaIsler.length,
      toplamKazanc: markaIsler.filter(i => i.durum !== 'reddedildi').reduce((s, i) => s + (Number(i.tutar) || 0), 0),
      sonOdeme: markaIsler.filter(i => i.tahsilTarihi).sort((a, b) => (b.tahsilTarihi > a.tahsilTarihi ? 1 : -1))[0] || null,
    };
  }
  return sonuc;
}

async function benzerMarkaBul(key) {
  const kayit = crm.markalar[key];
  if (!kayit) throw new Error('Marka bulunamadı');
  const prompt = `${kullaniciTanim()} "${kayit.ad}" markasıyla çalıştı.
"${kayit.ad}" benzeri, influencer iş birliği yapma ihtimali yüksek 10-15 marka öner (aynı sektör/benzer ürünler, sponsorluk bütçesi olan).
SADECE JSON dön: [{"marka":"Ugreen","neden":"kısa neden","website":"ugreen.com"}]`;
  const liste = await geminiJson(prompt, { maxTokens: 4096 });
  kayit.benzerMarkalar = { liste, at: Date.now() };
  saveCrm();
  return kayit.benzerMarkalar;
}

// ─── Gelir paneli + Ödeme takibi + FOMO ──────────────────────────────────────
function gelirVerisi() {
  const simdi = Date.now();
  const ayBasi = new Date(); ayBasi.setDate(1); ayBasi.setHours(0, 0, 0, 0);
  const buAyMs = ayBasi.getTime();

  const buAyTeklif = Object.values(db.emails).filter(e =>
    e.date >= buAyMs && COLLAB_KATEGORILER.includes(e.kategori) && e.kategori !== 'tamamlanan').length;
  const kabul = isler.liste.filter(i => i.olusturuldu >= buAyMs && i.durum !== 'reddedildi').length;
  const red = isler.liste.filter(i => i.olusturuldu >= buAyMs && i.durum === 'reddedildi').length;

  // ödeme takibi
  const odemeTakibi = isler.liste
    .filter(i => i.durum !== 'reddedildi' && i.tutar)
    .map(i => {
      const yayinMs = i.yayinTarihi ? new Date(i.yayinTarihi).getTime() : null;
      const beklenenMs = yayinMs ? yayinMs + (Number(i.odemeSartiGun) || 30) * 86400000 : null;
      const gecikmeGun = (!i.tahsilTarihi && beklenenMs && simdi > beklenenMs)
        ? Math.floor((simdi - beklenenMs) / 86400000) : 0;
      return { ...i, beklenenOdeme: beklenenMs, gecikmeGun,
        odemeDurumu: i.tahsilTarihi ? 'odendi' : (gecikmeGun > 0 ? 'gecikmis' : (yayinMs && simdi > yayinMs ? 'bekliyor' : 'henuz')) };
    })
    .sort((a, b) => b.gecikmeGun - a.gecikmeGun);

  const bekleyenOdeme = odemeTakibi.filter(i => !i.tahsilTarihi && i.odemeDurumu !== 'henuz')
    .reduce((s, i) => s + (Number(i.tutar) || 0), 0);
  const tahsilEdilen = isler.liste.filter(i => i.tahsilTarihi && new Date(i.tahsilTarihi).getTime() >= buAyMs)
    .reduce((s, i) => s + (Number(i.tutar) || 0), 0);

  // son 6 ay tahsilat grafiği
  const aylik = [];
  for (let g = 5; g >= 0; g--) {
    const d = new Date(); d.setDate(1); d.setHours(0, 0, 0, 0); d.setMonth(d.getMonth() - g);
    const son = new Date(d); son.setMonth(son.getMonth() + 1);
    const toplam = isler.liste.filter(i => i.tahsilTarihi &&
      new Date(i.tahsilTarihi) >= d && new Date(i.tahsilTarihi) < son)
      .reduce((s, i) => s + (Number(i.tutar) || 0), 0);
    aylik.push({ ay: d.toLocaleDateString('tr-TR', { month: 'short' }), toplam });
  }

  // marka karlılık tablosu
  const markaMap = {};
  for (const i of isler.liste.filter(i => i.durum !== 'reddedildi')) {
    const k = markaKey(i.marka) || '_diger';
    if (!markaMap[k]) markaMap[k] = { marka: i.marka, toplam: 0, isSayisi: 0 };
    markaMap[k].toplam += Number(i.tutar) || 0;
    markaMap[k].isSayisi++;
  }
  const markaTablosu = Object.values(markaMap).sort((a, b) => b.toplam - a.toplam);

  // FOMO uyarıları
  const fomo = [];
  const threadSayilari = {};
  for (const e of Object.values(db.emails)) {
    if (!e.threadId) continue;
    threadSayilari[e.threadId] = (threadSayilari[e.threadId] || 0) + 1;
  }
  for (const e of Object.values(db.emails)) {
    if (e.arsivlendi || !['yeni_isbirligi', 'teklif_bekleyen', 'gorusme'].includes(e.kategori)) continue;
    const gun = Math.floor((simdi - e.date) / 86400000);
    if (gun >= 5 && gun <= 30) {
      fomo.push({ tip: 'soguyor', marka: e.marka || e.from, emailId: e.id, gun,
        mesaj: `${e.marka || e.from}: ${gun} gündür hareket yok — teklif soğuyor olabilir.` });
    }
    if ((threadSayilari[e.threadId] || 0) >= 3 && gun <= 7) {
      fomo.push({ tip: 'sicak', marka: e.marka || e.from, emailId: e.id, gun,
        mesaj: `${e.marka || e.from}: aynı konuda ${threadSayilari[e.threadId]} mail — kapanma ihtimali yüksek, hızlı dön!` });
    }
  }
  fomo.sort((a, b) => (a.tip === 'sicak' ? -1 : 1) - (b.tip === 'sicak' ? -1 : 1));

  return {
    buAy: { toplamTeklif: buAyTeklif, kabul, red, bekleyenOdeme, tahsilEdilen },
    aylik, markaTablosu, odemeTakibi, fomo: fomo.slice(0, 12),
    icgoruler: db.icgoruler,
  };
}

async function icgorulerUret() {
  const g = gelirVerisi();
  const crmData = crmVerisi();
  const puanlar = Object.values(crmData).filter(m => m.puan).map(m => `${m.ad}: ${m.puan}/5 ${m.etiketler.join(',')}`);
  const prompt = `Sen ${kullaniciTanim()}'nın iş analistisin. Eldeki verilere göre kısa ve net içgörüler üret.

FİYAT LİSTESİ: ${memory.fiyatlar.map(f => `${f.ad}: $${f.fiyat}`).join(' | ')}
İŞLER: ${JSON.stringify(isler.liste.map(i => ({ marka: i.marka, tutar: i.tutar, durum: i.durum, yayin: i.yayinTarihi, tahsil: i.tahsilTarihi })))}
AYLIK TAHSİLAT: ${JSON.stringify(g.aylik)}
MARKA PUANLARI: ${puanlar.join(' | ') || 'henüz puan yok'}
AKTİF TEKLİF SAYISI: ${g.buAy.toplamTeklif}

SADECE JSON dön:
{
 "enKarliMarka": "marka + 1 cümle (veri yoksa 'Henüz yeterli veri yok')",
 "enAzUgrastiran": "yüksek puan + az revizyon kombinasyonuna göre, 1 cümle",
 "zamOnerisi": "iş hacmi ve talebe bakarak fiyat güncelleme önerisi, somut rakamlarla, 1-2 cümle",
 "digerIcgoruler": ["en fazla 3 kısa içgörü"]
}`;
  const r = await geminiJson(prompt, { maxTokens: 4096 });
  db.icgoruler = { ...r, at: Date.now() };
  markDirty();
  return db.icgoruler;
}

// ─── İş önerisi (mailden işe dönüştür) ───────────────────────────────────────
async function isOner(email) {
  const bugun = new Date().toISOString().slice(0, 10);
  const prompt = `Bugün: ${bugun}. Aşağıdaki iş birliği mailinden bir iş kaydı çıkar.
MAİL (${email.from}, "${email.subject}"):
${(email.body || email.snippet).slice(0, 3000)}
${email.analiz ? 'AI ANALİZİ: ' + JSON.stringify(email.analiz.teklifOzeti) + ' Önerilen toplam: $' + (email.analiz.degerlendirme?.toplam || 0) : ''}

SADECE JSON dön:
{
 "baslik": "kısa iş adı (örn: Anker Solix Reel + 2 Story)",
 "marka": "...",
 "tutar": 3500,
 "yayinTarihi": "YYYY-MM-DD (mailde belirtilmişse o, yoksa bugünden ~2 hafta sonrası)",
 "odemeSartiGun": 30,
 "takvim": [{"tarih": "YYYY-MM-DD", "etiket": "Script Teslim"}, {"tarih": "YYYY-MM-DD", "etiket": "Çekim"}, {"tarih": "YYYY-MM-DD", "etiket": "Yayın"}]
}`;
  return geminiJson(prompt, { maxTokens: 2048 });
}

// ─── İçerik üretimi (fikir / senaryo) ────────────────────────────────────────
async function icerikUret(email, tip) {
  const brief = (email.body || email.snippet).slice(0, 5000);
  const gorevler = {
    fikirler: 'Bu brief/mail için kullanıcının tarzında (samimi anlatım, Türkçe) 10 farklı video fikri üret. Her fikir: çarpıcı başlık + 1-2 cümle konsept + hook önerisi. Numaralı liste halinde yaz.',
    reel: '60 saniyelik Instagram Reel senaryosu yaz (Türkçe). Format: HOOK (0-3sn), bölüm bölüm saniye aralıklarıyla konuşma metni + görüntü önerileri, CTA ile bitir. Sponsor entegrasyonu doğal olsun.',
    youtube: '8-12 dakikalık YouTube videosu senaryosu yaz (Türkçe). Format: başlık önerileri (3 adet), hook, bölüm bölüm akış (her bölüm: konuşma ana hatları + B-roll önerileri), sponsor entegrasyon noktası, kapanış CTA.',
  };
  const prompt = `Sen ${kullaniciTanim()}'nın içerik asistanısın (samimi-eğlenceli Türkçe anlatım).

MARKA/BRIEF MAİLİ (${email.marka || email.from}):
${brief}

GÖREV: ${gorevler[tip] || gorevler.fikirler}`;
  const text = await gemini(prompt, { maxTokens: 8192 });
  if (!email.icerik) email.icerik = {};
  email.icerik[tip] = { text, at: Date.now() };
  markDirty();
  return text;
}

// ─── Sözleşme merkezi ────────────────────────────────────────────────────────
const SOZLESME_UZANTILAR = /\.(pdf|docx?|txt)$/i;

function sozlesmeListesi() {
  const liste = [];
  for (const e of Object.values(db.emails)) {
    for (const a of (e.attachments || [])) {
      if (!SOZLESME_UZANTILAR.test(a.name)) continue;
      const anahtar = e.id + '|' + a.name;
      liste.push({
        emailId: e.id, dosya: a.name, mimeType: a.mimeType,
        marka: e.marka || e.from, konu: e.subject, tarih: e.date,
        analiz: db.sozlesmeler[anahtar] || null,
      });
    }
  }
  return liste.sort((a, b) => b.tarih - a.tarih);
}

async function sozlesmeAnaliz(emailId, dosyaAdi) {
  const anahtar = emailId + '|' + dosyaAdi;
  if (db.sozlesmeler[anahtar]) return db.sozlesmeler[anahtar];

  const r = await gmail.users.messages.get({ userId: 'me', id: emailId, format: 'full' });
  let hedef = null;
  (function bul(p) {
    if (!p) return;
    if (p.filename === dosyaAdi && p.body?.attachmentId) hedef = p;
    (p.parts || []).forEach(bul);
  })(r.data.payload);
  if (!hedef) throw new Error('Ek bulunamadı: ' + dosyaAdi);

  const att = await gmail.users.messages.attachments.get({ userId: 'me', messageId: emailId, id: hedef.body.attachmentId });
  const b64 = att.data.data.replace(/-/g, '+').replace(/_/g, '/');

  const soru = `Bu belge bir influencer iş birliği eki (sözleşme/NDA/brief olabilir). ${kullaniciAd()} (içerik üreticisi) için analiz et.
SADECE JSON dön:
{
 "tur": "Sözleşme|NDA|Brief|Diğer",
 "ozet": "2-3 cümle: belge ne içeriyor",
 "kritikMaddeler": [{"uyari": "12 ay rakip marka yasağı", "detay": "ilgili madde özeti", "onem": "yuksek|orta|dusuk"}],
 "tavsiyeler": ["içerik üreticisi lehine pazarlık edilmesi gereken en fazla 3 nokta"]
}
Özellikle şunlara dikkat: münhasırlık/rakip yasağı, içerik kullanım hakları (süre/mecra/sınırsız mı), revizyon sınırı, ödeme şartları ve gecikme, fesih, cezai şartlar, onay süreçleri.`;

  let parts;
  if (/\.pdf$/i.test(dosyaAdi)) {
    parts = [{ inline_data: { mime_type: 'application/pdf', data: b64 } }, { text: soru }];
  } else if (/\.txt$/i.test(dosyaAdi)) {
    parts = [{ text: 'BELGE:\n' + Buffer.from(b64, 'base64').toString('utf8').slice(0, 30000) + '\n\n' + soru }];
  } else {
    throw new Error('Şimdilik sadece PDF ve TXT analiz edilebiliyor (.doc/.docx için PDF iste)');
  }
  const analiz = await geminiJson(parts, { maxTokens: 8192 });
  db.sozlesmeler[anahtar] = { ...analiz, at: Date.now() };
  markDirty();
  return db.sozlesmeler[anahtar];
}

// ─── Tahsilat asistanı ───────────────────────────────────────────────────────
async function hatirlatmaUret(is, ton) {
  const tonlar = {
    nazik: 'Nazik ve dostane bir ödeme hatırlatması. İlişkiyi koruyan, anlayışlı bir dil.',
    sert: 'Ciddi ve net bir hatırlatma. Profesyonel ama kararlı; ödeme tarihinin geçtiğini açıkça vurgula.',
    son: 'Son uyarı. Resmi ve soğuk; bir sonraki adımın yasal süreç/iş ilişkisini sonlandırma olacağını belirt, yine de profesyonel kal.',
  };
  const email = is.emailId ? db.emails[is.emailId] : null;
  const dil = email && /[çğıöşüÇĞİÖŞÜ]/.test(email.body || '') ? 'Türkçe' : 'mailin dilinde (muhtemelen İngilizce)';
  const prompt = `Sen ${kullaniciTanim()}'nın mail asistanısın. Geciken ödeme için hatırlatma maili yaz.

İŞ: ${is.baslik} | Marka: ${is.marka} | Tutar: $${is.tutar}
Yayın tarihi: ${is.yayinTarihi || 'bilinmiyor'} | Ödeme şartı: ${is.odemeSartiGun || 30} gün
${email ? 'İlgili kişi: ' + email.from + ' <' + email.fromEmail + '>' : ''}
TON: ${tonlar[ton] || tonlar.nazik}

${dil} yaz. SADECE mail gövdesini dön, açıklama ekleme. İmza: ${kullaniciAd()}.`;
  const cevap = (await gemini(prompt, { maxTokens: 1536 })).trim();
  let turkce = '';
  try { turkce = await googleCevir(cevap); } catch {}
  return { cevap, turkce };
}

// ─── İstatistikler ───────────────────────────────────────────────────────────
function getStats() {
  const all = Object.values(db.emails).filter(e => !e.arsivlendi);
  const ayBasi = new Date(); ayBasi.setDate(1); ayBasi.setHours(0, 0, 0, 0);
  const buAy = Object.values(db.emails).filter(e => e.date >= ayBasi.getTime());
  const collab = k => all.filter(e => e.kategori === k).length;
  return {
    kategoriler: {
      yeni_isbirligi: collab('yeni_isbirligi'),
      teklif_bekleyen: collab('teklif_bekleyen'),
      gorusme: collab('gorusme'),
      icerik_uretim: collab('icerik_uretim'),
      odeme_bekleyen: collab('odeme_bekleyen'),
      tamamlanan: Object.values(db.emails).filter(e => e.kategori === 'tamamlanan').length,
      spam_dolandirici: collab('spam_dolandirici'),
      diger: collab('diger'),
    },
    buAy: {
      gelenTeklif: buAy.filter(e => ['yeni_isbirligi', 'teklif_bekleyen', 'gorusme'].includes(e.kategori)).length,
      gorusmede: collab('gorusme') + collab('teklif_bekleyen'),
      uretimde: collab('icerik_uretim'),
      spamEngellendi: buAy.filter(e => e.kategori === 'spam_dolandirici').length,
    },
    okunmamis: all.filter(e => e.unread).length,
    kazancTahmini: db.kazancTahmini || null,
    lastSync: db.lastSync,
    syncing,
    lastSyncError,
  };
}

// ─── HTTP API ────────────────────────────────────────────────────────────────
const app = express();
app.use(express.json({ limit: '15mb' })); // media kit görselleri base64 gelir

// ─── Erişim koruması ─────────────────────────────────────────────────────────
// Kendi bilgisayarın (localhost) her zaman serbest. Ağ/telefon üzerinden erişim,
// kullanıcı bir PIN belirlemişse PIN ister — böylece aynı Wi-Fi'deki başkaları giremez.
function localhostMu(req) {
  const ip = (req.socket.remoteAddress || '').replace('::ffff:', '');
  return ip === '127.0.0.1' || ip === '::1' || ip === 'localhost';
}
app.use((req, res, next) => {
  const pin = memory.erisimPin;
  if (!pin) return next();                 // PIN belirlenmemiş → koruma kapalı
  if (localhostMu(req)) return next();      // kendi bilgisayarı → serbest
  const verilen = req.headers['x-dayi-pin'] || req.query.pin;
  if (verilen && String(verilen) === String(pin)) return next();
  if (req.path.startsWith('/api/')) return res.status(401).json({ error: 'Erişim PIN\'i gerekli', pinGerekli: true });
  next(); // statik sayfa serbest (PIN ekranı göstermek için)
});
// Arayüz tek HTML dosyası — pkg snapshot'ından da okunabilsin diye manuel sunulur.
app.get('/', (req, res) => {
  res.type('html').send(arayuzOku('index.html'));
});

function emailSummary(e) {
  const { body, analiz, ...rest } = e;
  return { ...rest, analizVar: !!analiz };
}

app.get('/api/state', (req, res) => {
  const emails = Object.values(db.emails)
    .filter(e => !e.arsivlendi)
    .sort((a, b) => b.date - a.date)
    .map(emailSummary);
  res.json({ emails, stats: getStats(), memory, yerelIP: yerelIP(), surum: SURUM, guncelleme: guncellemeBilgisi });
});

app.post('/api/sync', async (req, res) => {
  syncEmails(); // arka planda; durum /api/state'ten izlenir
  res.json({ ok: true, syncing: true });
});

app.get('/api/email/:id', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try {
    if (!e.analiz) await analyzeEmail(e);
    if (e.unread) {
      e.unread = false; markDirty();
      gmail.users.messages.modify({
        userId: 'me', id: e.id, requestBody: { removeLabelIds: ['UNREAD'] },
      }).catch(() => {});
    }
    res.json(e);
  } catch (err) {
    res.status(500).json({ error: err.message, email: e });
  }
});

let benimEmail = null;
async function threadGetir(e) {
  if (!benimEmail) benimEmail = (await gmail.users.getProfile({ userId: 'me' })).data.emailAddress;
  const t = await gmail.users.threads.get({ userId: 'me', id: e.threadId, format: 'full' });
  return (t.data.messages || []).map(msg => {
    const headers = msg.payload?.headers || [];
    const fromRaw = getHeader(headers, 'From');
    const m = fromRaw.match(/^(?:"?([^"<]*)"?\s*)?<?([^<>\s]+@[^<>\s]+)>?$/);
    const fromEmail = m?.[2] || fromRaw;
    const { ana } = alintiAyikla(extractBody(msg.payload));
    return {
      id: msg.id,
      from: (m?.[1] || '').trim() || fromEmail,
      fromEmail,
      date: Number(msg.internalDate) || 0,
      ana: ana || msg.snippet || '',
      benden: fromEmail.toLowerCase() === benimEmail.toLowerCase(),
    };
  }).sort((a, b) => a.date - b.date);
}

app.get('/api/email/:id/thread', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try { res.json({ mesajlar: await threadGetir(e) }); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/email/:id/cevir', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try {
    const mesajlar = await threadGetir(e);
    if (!e.threadCeviri) e.threadCeviri = {};
    // Google Çeviri ile mesaj mesaj — anında döner, Gemini kotasına dokunmaz
    const eksikler = mesajlar.filter(m => !e.threadCeviri[m.id]);
    let hataSayisi = 0;
    await Promise.all(eksikler.map(async m => {
      if (!m.ana.trim()) { e.threadCeviri[m.id] = m.ana; return; }
      try {
        const t = await googleCevir(m.ana.slice(0, 6000));
        if (t) e.threadCeviri[m.id] = t;
      } catch { hataSayisi++; }
    }));
    markDirty();
    if (!Object.keys(e.threadCeviri).length) throw new Error('Çeviri yapılamadı, biraz sonra tekrar dene');
    res.json({ ceviriler: e.threadCeviri, eksik: hataSayisi });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/email/:id/reply', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try {
    const r = await generateReply(e, req.body || {});
    res.json(r);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/email/:id/draft', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  const body = (req.body?.body || '').trim();
  if (!body) return res.status(400).json({ error: 'Mail içeriği boş' });
  try {
    const draft = await saveDraft(e, body);
    res.json({ ok: true, id: draft.id });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/tahmin', async (req, res) => {
  try { res.json({ ok: true, kazancTahmini: await estimateEarnings() }); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/email/:id/send', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  const body = (req.body?.body || '').trim();
  if (!body) return res.status(400).json({ error: 'Mail içeriği boş' });
  try {
    const ekler = req.body?.istatistikEkle ? (memory.mediaKit?.gorseller || []) : [];
    const sent = await sendReply(e, body, ekler);
    e.kategori = e.kategori === 'yeni_isbirligi' ? 'teklif_bekleyen' : e.kategori;
    e.cevaplandiAt = Date.now();
    markDirty();
    res.json({ ok: true, id: sent.id });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/email/:id/action', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  const { action } = req.body || {};
  try {
    if (action === 'archive') {
      await gmail.users.messages.modify({ userId: 'me', id: e.id, requestBody: { removeLabelIds: ['INBOX'] } });
      e.arsivlendi = true;
    } else if (action === 'spam') {
      await gmail.users.messages.modify({ userId: 'me', id: e.id, requestBody: { addLabelIds: ['SPAM'], removeLabelIds: ['INBOX'] } });
      e.arsivlendi = true; e.kategori = 'spam_dolandirici';
    } else if (action === 'star') {
      e.starred = !e.starred;
      await gmail.users.messages.modify({
        userId: 'me', id: e.id,
        requestBody: e.starred ? { addLabelIds: ['STARRED'] } : { removeLabelIds: ['STARRED'] },
      });
    } else if (action === 'kategori' && KATEGORILER.includes(req.body.kategori)) {
      e.kategori = req.body.kategori;
    }
    markDirty();
    res.json({ ok: true, email: emailSummary(e) });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/memory', (req, res) => {
  const m = req.body || {};
  const izinli = ['fiyatlar', 'donusSuresi', 'odemeYontemi', 'sevilenKategoriler', 'sevilmeyenKategoriler', 'profil', 'mediaKit', 'sablonlar', 'faturaBilgileri', 'menuAyarlari', 'eklentiler'];
  let degisti = false;
  for (const k of izinli) {
    if (m[k] !== undefined) { memory[k] = m[k]; degisti = true; }
  }
  if (degisti) saveJson(MEMORY_PATH, memory);
  res.json({ ok: true, memory });
});

app.post('/api/erisim-pin', (req, res) => {
  const pin = String(req.body?.pin || '').trim();
  if (pin) memory.erisimPin = pin; else delete memory.erisimPin;
  saveJson(MEMORY_PATH, memory);
  res.json({ ok: true, pinli: !!pin });
});

// Gemini API anahtarlarını ayarlardan değiştir (çalışma anında geçerli olur)
app.get('/api/gemini-anahtar', (req, res) => {
  res.json({ anahtarlar: GEMINI_KEYS.map(maskeAnahtar), adet: GEMINI_KEYS.length });
});
app.post('/api/gemini-anahtar', (req, res) => {
  const ham = req.body?.anahtarlar;
  const liste = (Array.isArray(ham) ? ham : String(ham || '').split(/[\s,]+/))
    .map(s => String(s).trim()).filter(Boolean);
  if (!liste.length) return res.status(400).json({ error: 'En az bir Gemini API anahtarı girin.' });
  if (liste.some(k => !/^AIza[0-9A-Za-z_\-]{30,}$/.test(k)))
    return res.status(400).json({ error: 'Anahtarlar "AIza..." ile başlamalı (geçersiz biçim).' });
  cfg = cfg || {};
  cfg.geminiKeys = liste;
  try { saveJson(CONFIG_PATH, cfg); } catch (e) { return res.status(500).json({ error: 'Kaydedilemedi: ' + e.message }); }
  GEMINI_KEYS = liste;
  res.json({ ok: true, adet: liste.length, anahtarlar: liste.map(maskeAnahtar) });
});

app.post('/api/memory/not', (req, res) => {
  const text = (req.body?.text || '').trim();
  if (text) {
    memory.notlar.push({ text, at: Date.now() });
    saveJson(MEMORY_PATH, memory);
  }
  res.json({ ok: true, memory });
});

app.delete('/api/memory/not/:index', (req, res) => {
  const i = Number(req.params.index);
  if (i >= 0 && i < memory.notlar.length) {
    memory.notlar.splice(i, 1);
    saveJson(MEMORY_PATH, memory);
  }
  res.json({ ok: true, memory });
});

// ─── CRM uçları ──────────────────────────────────────────────────────────────
app.get('/api/crm', (req, res) => res.json({ markalar: crmVerisi() }));

app.post('/api/crm/:key', (req, res) => {
  const kayit = crm.markalar[req.params.key];
  if (!kayit) return res.status(404).json({ error: 'Marka bulunamadı' });
  const { puan, etiketler, notlar } = req.body || {};
  if (puan !== undefined) kayit.puan = puan ? Math.min(5, Math.max(1, Number(puan))) : null;
  if (Array.isArray(etiketler)) kayit.etiketler = etiketler;
  if (notlar !== undefined) kayit.notlar = String(notlar);
  saveCrm();
  res.json({ ok: true });
});

app.post('/api/crm/:key/benzer', async (req, res) => {
  try { res.json(await benzerMarkaBul(req.params.key)); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── İş / Gelir / Takvim uçları ──────────────────────────────────────────────
app.get('/api/gelir', (req, res) => res.json(gelirVerisi()));

app.post('/api/gelir/icgoruler', async (req, res) => {
  try { res.json(await icgorulerUret()); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

app.get('/api/isler', (req, res) => res.json({ liste: isler.liste }));

app.post('/api/isler', (req, res) => {
  const i = req.body || {};
  if (!i.baslik || !i.marka) return res.status(400).json({ error: 'Başlık ve marka zorunlu' });
  if (i.id) {
    const idx = isler.liste.findIndex(x => x.id === i.id);
    if (idx === -1) return res.status(404).json({ error: 'İş bulunamadı' });
    isler.liste[idx] = { ...isler.liste[idx], ...i };
  } else {
    i.id = 'is_' + Date.now();
    i.olusturuldu = Date.now();
    i.durum = i.durum || 'anlasildi';
    isler.liste.push(i);
    // marka CRM'de yoksa oluştur
    const key = markaKey(i.marka);
    if (key && !crm.markalar[key]) {
      crm.markalar[key] = { ad: i.marka, puan: null, etiketler: [], notlar: '', benzerMarkalar: null };
      saveCrm();
    }
  }
  saveIsler();
  res.json({ ok: true, is: isler.liste.find(x => x.id === i.id) });
});

app.delete('/api/isler/:id', (req, res) => {
  isler.liste = isler.liste.filter(i => i.id !== req.params.id);
  saveIsler();
  res.json({ ok: true });
});

app.post('/api/isler/oner/:emailId', async (req, res) => {
  const e = db.emails[req.params.emailId];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try { res.json(await isOner(e)); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/isler/:id/hatirlatma', async (req, res) => {
  const is = isler.liste.find(i => i.id === req.params.id);
  if (!is) return res.status(404).json({ error: 'İş bulunamadı' });
  try { res.json(await hatirlatmaUret(is, req.body?.ton || 'nazik')); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── Sözleşme uçları ─────────────────────────────────────────────────────────
app.get('/api/sozlesmeler', (req, res) => res.json({ liste: sozlesmeListesi() }));

app.post('/api/sozlesme/analiz', async (req, res) => {
  const { emailId, dosya } = req.body || {};
  if (!emailId || !dosya) return res.status(400).json({ error: 'emailId ve dosya gerekli' });
  try { res.json(await sozlesmeAnaliz(emailId, dosya)); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── AI Bütçe Önerisi (fiyat listesinden bağımsız) ───────────────────────────
app.post('/api/email/:id/butce', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try {
    const gecmisIsler = isler.liste.filter(i => i.durum !== 'reddedildi' && i.tutar);
    const ortalama = gecmisIsler.length
      ? Math.round(gecmisIsler.reduce((s, i) => s + Number(i.tutar), 0) / gecmisIsler.length) : null;
    const kayit = crm.markalar[markaKey(e.marka)];
    const prompt = `Sen influencer pazarlaması konusunda uzman bir fiyat stratejistisin. ${kullaniciAd()} için bu markaya özel, REFERANS LİSTEDEN BAĞIMSIZ bir fiyat teklifi oluştur.

INFLUENCER PROFİLİ:
${mediaKitOzet() || 'YouTube: 1.2M abone, teknoloji/AI içerikleri (detaylı istatistik girilmemiş)'}
Türkiye'nin önde gelen teknoloji/AI içerik üreticilerinden; kitlesi teknoloji meraklısı, satın alma gücü yüksek.

GEÇMİŞ İŞ BİRLİKLERİ: ${gecmisIsler.length ? `${gecmisIsler.length} iş, ortalama anlaşma $${ortalama}; markalar: ${[...new Set(gecmisIsler.map(i => i.marka))].slice(0, 10).join(', ')}` : 'kayıtlı iş yok'}
${kayit?.puan ? `BU MARKAYLA GEÇMİŞ: ${kayit.puan}/5 puan (${(kayit.etiketler || []).join(', ')})` : ''}
SADECE REFERANS (bağlı kalma): ${memory.fiyatlar.map(f => `${f.ad}: $${f.fiyat}`).join(' | ')}

MARKANIN MAİLİ (${e.from}, "${e.subject}"):
${(e.body || e.snippet).slice(0, 3000)}
${e.analiz?.markaAnalizi ? 'MARKA ANALİZİ: ' + JSON.stringify(e.analiz.markaAnalizi) : ''}

Markanın büyüklüğünü, sektörünü, kampanya bütçe potansiyelini ve influencer'ın pazarlık gücünü tart. Büyük/köklü markaya yüksek fiyat, riskli/küçük markaya temkinli fiyat. İstenen içerik tipine göre kalem kalem fiyatla.

SADECE şu JSON'u dön:
{
 "kalemler": [{"ad": "YouTube Dedicated Video", "fiyat": 5000, "neden": "1 kısa cümle"}],
 "toplam": 5000,
 "aralik": {"min": 4000, "max": 6500},
 "strateji": "2-3 cümlelik pazarlık stratejisi: nereden başla, nereye kadar in, neyi vurgula"
}`;
    const oneri = await geminiJson(prompt, { maxTokens: 4096 });
    e.butceOnerisi = { ...oneri, at: Date.now() };
    markDirty();
    res.json(e.butceOnerisi);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── İçerik üretimi ──────────────────────────────────────────────────────────
app.post('/api/email/:id/icerik', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  const tip = req.body?.tip || 'fikirler';
  try {
    if (e.icerik?.[tip] && !req.body?.yenile) return res.json({ text: e.icerik[tip].text, cached: true });
    res.json({ text: await icerikUret(e, tip) });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── 📋 Eklentiler: Brief Uygunluk / İçerik Planı / Rapor Kartı / Sözleşme ───
app.post('/api/email/:id/brief-uygunluk', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  const icerik = (req.body?.icerik || '').trim();
  if (!icerik) return res.status(400).json({ error: 'İçeriğini/senaryonu gir' });
  try {
    const prompt = `Marka brief'i (mailden):\n${(e.body || e.snippet).slice(0, 3500)}\n\nÜreticinin hazırladığı içerik/senaryo:\n${icerik.slice(0, 3500)}\n\nİçerik, marka brief'inin tüm şartlarını karşılıyor mu? SADECE JSON dön:\n{"uygunlukYuzde": 0-100, "karsilanan": ["karşılanan şartlar"], "eksik": ["eksik/atlanmış şartlar"], "oneriler": ["içeriği brief'e tam uydurmak için öneriler"]}`;
    res.json(await geminiJson(prompt, { maxTokens: 2048 }));
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/icerik-plani', async (req, res) => {
  try {
    const aktif = isler.liste.filter(i => ['anlasildi', 'icerik', 'yayinda'].includes(i.durum));
    if (!aktif.length) return res.json({ plan: [], oneri: 'Aktif iş yok. Bir maili "İşe Dönüştür" ile plana ekleyebilirsin.' });
    const prompt = `${kullaniciAd()} (içerik üreticisi) aktif işleri:\n${JSON.stringify(aktif.map(i => ({ marka: i.marka, is: i.baslik, yayin: i.yayinTarihi, durum: i.durum })), null, 1)}\nBunlar için pratik bir içerik üretim planı çıkar (hangi hafta hangi iş için ne yapılmalı: script, çekim, kurgu, yayın). SADECE JSON:\n{"plan": [{"hafta": "Bu Hafta", "gorevler": ["Anker videosu çekimi", "..."]}], "oneri": "1-2 cümle genel öneri"}`;
    res.json(await geminiJson(prompt, { maxTokens: 4096 }));
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/rapor-karti', async (req, res) => {
  const { marka, baslik, izlenme, etkilesim, notlar } = req.body || {};
  if (!marka) return res.status(400).json({ error: 'Marka gerekli' });
  try {
    const prompt = `${kullaniciTanim()} adına, "${marka}" markasına gönderilecek profesyonel bir İŞ SONUÇ RAPORU metni yaz.
İş: ${baslik || '-'} | İzlenme/Erişim: ${izlenme || 'belirtilmemiş'} | Etkileşim: ${etkilesim || 'belirtilmemiş'} | Notlar: ${notlar || '-'}
Mail formatında: kısa giriş, sonuç metrikleri (madde madde), kısa değerlendirme, teşekkür ve devam iş birliği teklifi. Türkçe, samimi-profesyonel. İmza: ${kullaniciAd()}.`;
    res.json({ metin: (await gemini(prompt, { maxTokens: 2048 })).trim() });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/sozlesme-uret', async (req, res) => {
  const { tur, marka, kapsam, ucret, sure } = req.body || {};
  if (!marka) return res.status(400).json({ error: 'Marka gerekli' });
  try {
    const prompt = `${tur || 'İçerik İş Birliği Sözleşmesi'} taslağı oluştur (Türkçe, resmi sözleşme formatı, numaralı maddeler).
Taraflar: "${kullaniciAd()}" (içerik üreticisi/yüklenici) ve "${marka}" (marka/işveren).
Kapsam: ${kapsam || 'belirtilmemiş'} | Ücret: ${ucret || 'belirtilmemiş'} | Süre/Kullanım hakları: ${sure || 'belirtilmemiş'}
İçerik üreticisini koruyan dengeli maddeler ekle: teslim, ödeme şartı ve gecikme, içerik onay/revizyon sınırı, kullanım hakları süresi/mecra, münhasırlık, fesih. Başına şu notu yaz: "⚠️ Bu bir taslaktır, hukuki danışmanlık yerine geçmez; imzalamadan önce avukata danışın."`;
    res.json({ metin: (await gemini(prompt, { maxTokens: 6144 })).trim() });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── 🎙️ Sesli okuma (ElevenLabs TTS) ────────────────────────────────────────
const ELEVENLABS_KEY = (cfg && cfg.elevenLabsKey) || process.env.ELEVENLABS_KEY || '4678e122adbed8d29ad82b4c3366df468449c2cb1faa9427ba500a30f36e6c0b';
const ELEVENLABS_VOICE = (cfg && cfg.elevenLabsVoice) || process.env.ELEVENLABS_VOICE || '7VqWGAWwo2HMrylfKrcm';

// Metin Türkçe mi? (değilse okumadan önce Türkçeye çevrilecek)
function turkceMi(t) {
  if (/[çğıöşüÇĞİÖŞÜ]/.test(t)) return true;
  const trKelime = /\b(ve|bir|bu|için|ile|ama|çok|var|yok|merhaba|teşekkür|selam)\b/i;
  return trKelime.test(t);
}

app.post('/api/tts', async (req, res) => {
  let metin = (req.body?.metin || '').slice(0, 2500).trim();
  if (!metin) return res.status(400).json({ error: 'Okunacak metin yok' });
  // Her zaman Türkçe oku: Türkçe değilse çevir
  if (!turkceMi(metin)) {
    try { metin = await googleCevir(metin); } catch { /* çeviri başarısızsa orijinali oku */ }
  }
  try {
    const post = JSON.stringify({
      text: metin,
      model_id: 'eleven_multilingual_v2',
      voice_settings: { stability: 0.5, similarity_boost: 0.8 },
    });
    const r = https.request({
      hostname: 'api.elevenlabs.io',
      path: `/v1/text-to-speech/${ELEVENLABS_VOICE}`,
      method: 'POST',
      headers: { 'xi-api-key': ELEVENLABS_KEY, 'Content-Type': 'application/json', 'Accept': 'audio/mpeg' },
    }, ra => {
      if (ra.statusCode !== 200) {
        const ch = []; ra.on('data', c => ch.push(c));
        ra.on('end', () => { if (!res.headersSent) res.status(502).json({ error: 'Ses servisi: ' + Buffer.concat(ch).toString('utf8').slice(0, 200) }); });
        return;
      }
      res.setHeader('Content-Type', 'audio/mpeg');
      ra.on('error', () => { try { res.end(); } catch {} });
      ra.pipe(res);
    });
    r.on('error', e => { if (!res.headersSent) res.status(500).json({ error: e.message }); });
    r.setTimeout(30000, () => r.destroy());
    r.write(post); r.end();
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── 📨 Outreach (markalara kendin ulaş) ─────────────────────────────────────
async function yeniMailGonder(to, konu, bodyText) {
  const profile = await gmail.users.getProfile({ userId: 'me' });
  const me = profile.data.emailAddress;
  const lines = [
    `From: ${me}`, `To: ${to}`, `Subject: ${encodeSubject(konu)}`,
    'MIME-Version: 1.0', 'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: base64',
    '', Buffer.from(bodyText, 'utf8').toString('base64'),
  ];
  const raw = Buffer.from(lines.join('\r\n'), 'utf8').toString('base64url');
  return (await gmail.users.messages.send({ userId: 'me', requestBody: { raw } })).data;
}

app.post('/api/outreach/uret', async (req, res) => {
  const marka = (req.body?.marka || '').trim();
  const baglam = (req.body?.baglam || '').trim();
  const dil = req.body?.dil === 'en' ? 'İngilizce' : 'Türkçe';
  if (!marka) return res.status(400).json({ error: 'Marka adı gerekli' });
  try {
    const prompt = `Sen ${kullaniciTanim()}'nın asistanısın.
${kullaniciAd()}, "${marka}" markasıyla İŞ BİRLİĞİ YAPMAK İSTİYOR ve onlara ilk kez ulaşıyor (soğuk outreach). Kısa, profesyonel, samimi bir tanıtım/teklif maili yaz.
${baglam ? 'Ek bağlam: ' + baglam : ''}
${mediaKitOzet() ? 'Kanal istatistikleri (uygun yerde değin): ' + mediaKitOzet() : ''}
Mail: kendini ve kanalını kısaca tanıt, markaya neden uygun olduğunu belirt, iş birliği öner, medya kit/görüşme teklif et. Abartma, kısa tut.
${dil} yaz. SADECE şu JSON'u dön: {"konu": "mail konusu", "govde": "mail gövdesi (imza: ${kullaniciAd()})"}`;
    const r = await geminiJson(prompt, { maxTokens: 2048 });
    res.json(r);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/outreach/gonder', async (req, res) => {
  const { email, konu, govde } = req.body || {};
  if (!email || !konu || !govde) return res.status(400).json({ error: 'E-posta, konu ve içerik gerekli' });
  try { const s = await yeniMailGonder(email, konu, govde); res.json({ ok: true, id: s.id }); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

app.post('/api/outreach/taslak', async (req, res) => {
  const { email, konu, govde } = req.body || {};
  if (!email || !konu || !govde) return res.status(400).json({ error: 'Eksik bilgi' });
  try {
    const profile = await gmail.users.getProfile({ userId: 'me' });
    const lines = [`From: ${profile.data.emailAddress}`, `To: ${email}`, `Subject: ${encodeSubject(konu)}`,
      'MIME-Version: 1.0', 'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: base64', '',
      Buffer.from(govde, 'utf8').toString('base64')];
    const raw = Buffer.from(lines.join('\r\n'), 'utf8').toString('base64url');
    const d = await gmail.users.drafts.create({ userId: 'me', requestBody: { message: { raw } } });
    res.json({ ok: true, id: d.data.id });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── Güvenli otomatik güncelleme ─────────────────────────────────────────────
// Manifest senin gizli anahtarınla imzalı; uygulama gömülü açık anahtarla doğrular.
// Sahte güncelleme üretilemez; bozuk indirme SHA256 ile reddedilir; data/ korunur.
const GUNCELLEME_BASE = (cfg && cfg.guncellemeUrl) || process.env.DAYI_UPDATE_URL || 'http://76.13.76.68:8787/dayi/';
let guncellemeBilgisi = null;

function surumKarsilastir(a, b) {
  const pa = String(a).split('.').map(Number), pb = String(b).split('.').map(Number);
  for (let i = 0; i < 3; i++) { if ((pa[i] || 0) > (pb[i] || 0)) return 1; if ((pa[i] || 0) < (pb[i] || 0)) return -1; }
  return 0;
}

function httpGetBuf(url, redirectKalan = 3) {
  return new Promise((resolve, reject) => {
    const mod = url.startsWith('https') ? https : http;
    const req = mod.get(url, r => {
      if ([301, 302, 307, 308].includes(r.statusCode) && r.headers.location && redirectKalan > 0) {
        r.resume(); return resolve(httpGetBuf(r.headers.location, redirectKalan - 1));
      }
      if (r.statusCode !== 200) { r.resume(); return reject(new Error('HTTP ' + r.statusCode)); }
      const ch = [];
      r.on('data', c => ch.push(c));
      r.on('end', () => resolve(Buffer.concat(ch)));
    });
    req.on('error', reject);
    req.setTimeout(30000, () => req.destroy(new Error('zaman aşımı')));
  });
}

function manifestUrl(dosya) {
  return GUNCELLEME_BASE.replace(/\/?$/, '/') + dosya;
}

async function manifestGetir() {
  const manifestBuf = await httpGetBuf(manifestUrl('manifest.json'));
  const sig = (await httpGetBuf(manifestUrl('manifest.sig'))).toString('utf8').trim();
  if (!verifyData(manifestBuf, sig)) throw new Error('Güncelleme imzası geçersiz (güvenlik reddi)');
  return JSON.parse(manifestBuf.toString('utf8'));
}

async function guncellemeKontrol() {
  try {
    const m = await manifestGetir();
    guncellemeBilgisi = surumKarsilastir(m.surum, SURUM) > 0
      ? { surum: m.surum, notlar: m.notlar || '', tarih: m.tarih || '', mevcut: SURUM }
      : null;
  } catch (e) {
    // Host kapalı/erişilemez veya imza geçersiz → sessizce yok say (uygulama çalışmaya devam eder)
  }
}

function platformAnahtari() {
  if (process.platform === 'win32') return 'win';
  if (process.platform === 'darwin') return process.arch === 'arm64' ? 'macos-arm64' : 'macos';
  return 'linux';
}

const crypto2 = require('crypto');
function sha256(buf) { return crypto2.createHash('sha256').update(buf).digest('hex'); }

// Güncellemeyi indir, doğrula, kur (yalnızca paketlenmiş exe modunda)
async function guncellemeYap() {
  if (!SEA && !process.pkg) throw new Error('Güncelleme yalnızca kurulu uygulamada çalışır (geliştirme modunda değil).');
  const m = await manifestGetir();
  if (surumKarsilastir(m.surum, SURUM) <= 0) throw new Error('Zaten güncel sürümdesiniz.');
  const dosya = (m.dosyalar || {})[platformAnahtari()];
  if (!dosya || !dosya.url) throw new Error('Bu işletim sistemi için güncelleme dosyası yok.');

  const yeniBuf = await httpGetBuf(dosya.url);
  if (dosya.sha256 && sha256(yeniBuf).toLowerCase() !== String(dosya.sha256).toLowerCase()) {
    throw new Error('İndirilen dosya bütünlük doğrulamasından geçemedi (SHA256 uyuşmadı).');
  }
  const updateDir = path.join(DATA_DIR, 'update');
  fs.mkdirSync(updateDir, { recursive: true });
  const isWin = process.platform === 'win32';
  const yeniYol = path.join(updateDir, isWin ? 'dayi-yeni.exe' : 'dayi-yeni');
  fs.writeFileSync(yeniYol, yeniBuf);
  if (!isWin) fs.chmodSync(yeniYol, 0o755);

  const eski = process.execPath;
  if (isWin) {
    const bat = path.join(updateDir, 'guncelle.bat');
    fs.writeFileSync(bat,
      `@echo off\r\ntimeout /t 2 /nobreak >nul\r\n:retry\r\nmove /y "${yeniYol}" "${eski}" >nul 2>&1\r\n` +
      `if errorlevel 1 ( timeout /t 1 /nobreak >nul & goto retry )\r\nstart "" "${eski}"\r\ndel "%~f0"\r\n`);
    spawn('cmd.exe', ['/c', bat], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
  } else {
    const sh = path.join(updateDir, 'guncelle.sh');
    fs.writeFileSync(sh,
      `#!/bin/bash\nsleep 2\nmv -f "${yeniYol}" "${eski}"\nchmod +x "${eski}"\n` +
      `(open "${eski}" 2>/dev/null || "${eski}" >/dev/null 2>&1 &)\nrm -- "$0"\n`);
    fs.chmodSync(sh, 0o755);
    spawn('/bin/bash', [sh], { detached: true, stdio: 'ignore' }).unref();
  }
  // Ana süreç kısa süre sonra kapanır; updater eski exe'yi yenisiyle değiştirip yeniden başlatır.
  setTimeout(() => process.exit(0), 800);
  return { ok: true, yeniSurum: m.surum };
}

// ─── Brief özetleyici ────────────────────────────────────────────────────────
app.post('/api/email/:id/brief-ozet', async (req, res) => {
  const e = db.emails[req.params.id];
  if (!e) return res.status(404).json({ error: 'Mail bulunamadı' });
  try {
    if (e.briefOzet && !req.body?.yenile) return res.json(e.briefOzet);
    const prompt = `Aşağıdaki marka iş birliği mailini/brief'ini ${kullaniciAd()} için kısa ve net özetle.
MAİL (${e.from}, "${e.subject}"):
${(e.body || e.snippet).slice(0, 5000)}

SADECE şu JSON'u dön (bilinmeyen alana "Belirtilmemiş" yaz, uydurma):
{
 "neIstiyorlar": "1-2 cümle: marka ne istiyor",
 "icerikler": ["istenen içerik tipleri, madde madde"],
 "butce": "...", "teslimTarihi": "...", "kullanimHaklari": "...",
 "dikkat": ["dikkat edilmesi gereken en fazla 3 nokta (münhasırlık, revizyon, vb.)"]
}`;
    const ozet = await geminiJson(prompt, { maxTokens: 2048 });
    e.briefOzet = ozet; markDirty();
    res.json(ozet);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── Döviz çevirici (ücretsiz, anahtarsız) ───────────────────────────────────
let dovizCache = { at: 0, kurlar: null };
// Birden çok ücretsiz/anahtarsız kaynak — biri erişilemezse sıradakine geçer.
// Hepsi USD bazlı; 1 USD'nin TRY/EUR/GBP karşılığını döndürür.
async function dovizKurlariCek() {
  const kaynaklar = [
    { url: 'https://open.er-api.com/v6/latest/USD', al: d => d.rates },
    { url: 'https://api.exchangerate-api.com/v4/latest/USD', al: d => d.rates },
    { url: 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/usd.json',
      al: d => ({ TRY: d.usd?.try, EUR: d.usd?.eur, GBP: d.usd?.gbp }) },
    { url: 'https://latest.currency-api.pages.dev/v1/currencies/usd.json',
      al: d => ({ TRY: d.usd?.try, EUR: d.usd?.eur, GBP: d.usd?.gbp }) },
  ];
  for (const k of kaynaklar) {
    try {
      const buf = await httpGetBuf(k.url);
      const r = k.al(JSON.parse(buf.toString('utf8')));
      if (r && r.TRY) return r;
    } catch { /* sıradaki kaynağı dene */ }
  }
  throw new Error('Hiçbir döviz kaynağına ulaşılamadı (internet/ağ kontrol)');
}
app.get('/api/doviz', async (req, res) => {
  if (dovizCache.kurlar && Date.now() - dovizCache.at < 3600000) return res.json(dovizCache.kurlar);
  try {
    const r = await dovizKurlariCek();
    const kurlar = {
      USD_TRY: +Number(r.TRY).toFixed(2),
      EUR_TRY: r.EUR ? +(r.TRY / r.EUR).toFixed(2) : null,
      GBP_TRY: r.GBP ? +(r.TRY / r.GBP).toFixed(2) : null,
      tarih: new Date().toLocaleDateString('tr-TR'),
      kaynak: 'otomatik',
    };
    dovizCache = { at: Date.now(), kurlar };
    memory.usdTry = kurlar.USD_TRY; saveJson(MEMORY_PATH, memory); // son bilineni sakla
    res.json(kurlar);
  } catch (err) {
    // Otomatik alınamadı (internet/ağ kısıtlı) → elle girilen kuru kullan
    if (memory.usdTry) {
      return res.json({
        USD_TRY: memory.usdTry, EUR_TRY: null, GBP_TRY: null,
        tarih: 'elle girilen', kaynak: 'manuel',
        uyari: 'Otomatik kur alınamadı, elle girdiğin kur kullanılıyor.',
      });
    }
    res.status(503).json({ error: 'Otomatik kur alınamadı; lütfen kuru elle gir.', manuelGerekli: true });
  }
});

app.post('/api/doviz/manuel', (req, res) => {
  const v = Number(req.body?.usdTry);
  if (!v || v <= 0) return res.status(400).json({ error: 'Geçerli bir kur gir (örn. 46)' });
  memory.usdTry = +v.toFixed(2); saveJson(MEMORY_PATH, memory);
  dovizCache = { at: 0, kurlar: null };
  res.json({ ok: true, USD_TRY: memory.usdTry });
});

// ─── Yedekleme / geri yükleme ────────────────────────────────────────────────
app.get('/api/yedek', (req, res) => {
  const yedek = {
    surum: 1, tarih: new Date().toISOString(),
    memory, crm, isler,
  };
  res.setHeader('Content-Disposition', 'attachment; filename="dayi-yedek.json"');
  res.json(yedek);
});
app.post('/api/yedek/yukle', (req, res) => {
  const y = req.body || {};
  if (!y.memory && !y.crm && !y.isler) return res.status(400).json({ error: 'Geçersiz yedek dosyası.' });
  try {
    if (y.memory && typeof y.memory === 'object') { memory = y.memory; saveJson(MEMORY_PATH, memory); }
    if (y.crm && y.crm.markalar) { crm = y.crm; saveCrm(); }
    if (y.isler && Array.isArray(y.isler.liste)) { isler = y.isler; saveIsler(); }
    res.json({ ok: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── Güncelleme uçları ───────────────────────────────────────────────────────
app.get('/api/guncelleme-kontrol', async (req, res) => {
  await guncellemeKontrol();
  res.json({ surum: SURUM, guncelleme: guncellemeBilgisi });
});
app.post('/api/guncelle', async (req, res) => {
  try { res.json(await guncellemeYap()); }
  catch (err) { res.status(500).json({ error: err.message }); }
});

// ─── Başlat ──────────────────────────────────────────────────────────────────
function yerelIP() {
  const nets = os.networkInterfaces();
  const adaylar = [];
  for (const ad of Object.keys(nets)) {
    // Sanal adaptörleri ele (Hyper-V, WSL, Docker, VM'ler telefondan erişilemez)
    if (/vEthernet|WSL|Hyper-V|VirtualBox|VMware|Loopback|Default Switch/i.test(ad)) continue;
    for (const n of nets[ad] || []) {
      if (n.family !== 'IPv4' || n.internal) continue;
      if (/^192\.168\./.test(n.address)) adaylar.push({ ip: n.address, oncelik: 1 }); // ev Wi-Fi'si
      else if (/^10\./.test(n.address)) adaylar.push({ ip: n.address, oncelik: 2 });
      else if (/^172\.(1[6-9]|2\d|3[01])\./.test(n.address)) adaylar.push({ ip: n.address, oncelik: 3 });
    }
  }
  adaylar.sort((a, b) => a.oncelik - b.oncelik);
  return adaylar.length ? adaylar[0].ip : null;
}
app.listen(PORT, '0.0.0.0', () => {
  const ip = yerelIP();
  console.log(`\n  DAİ Mail Asistanı çalışıyor → http://localhost:${PORT}`);
  if (ip) console.log(`  Telefondan (aynı Wi-Fi):    http://${ip}:${PORT}\n`);
  // Manuel/ilk açılışta tarayıcıyı aç (bilgisayar açılışındaki sessiz autostart'ta açma)
  if (!process.argv.includes('--autostart')) {
    try {
      const url = `http://localhost:${PORT}`;
      if (process.platform === 'win32') spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
      else if (process.platform === 'darwin') spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
      else spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
    } catch {}
  }
  syncEmails();
  setInterval(syncEmails, 5 * 60 * 1000); // 5 dakikada bir otomatik senkron
  guncellemeKontrol(); // açılışta + saatte bir güncelleme kontrolü
  setInterval(guncellemeKontrol, 60 * 60 * 1000);
});
