# -*- coding: utf-8 -*-
"""
聊天记录 Web UI
运行: python scripts/chat_ui.py
访问: http://localhost:5678
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from flask import Flask, jsonify, render_template_string, request
import asyncio
from core.pydantic_ai_agent import CustomerServiceAgent, AgentDeps
from db import chat_log_db as db

app = Flask(__name__)
pricing_agent = None
try:
    pricing_agent = CustomerServiceAgent()
except Exception as e:
    print(f"[ChatUI] 初始化报价Agent失败: {e}")

HTML = r"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>聊天记录</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
         background: #1a1a2e; color: #e0e0e0; height: 100vh; display: flex; flex-direction: column; }

  /* ── 顶栏 ── */
  .topbar {
    background: #16213e; border-bottom: 1px solid #0f3460;
    padding: 12px 20px; display: flex; align-items: center; gap: 16px; flex-shrink: 0;
  }
  .topbar h1 { font-size: 16px; color: #4cc9f0; font-weight: 600; letter-spacing: 1px; }
  .search-box {
    flex: 1; max-width: 320px;
    background: #0f3460; border: 1px solid #1a5276;
    border-radius: 20px; padding: 6px 14px;
    color: #e0e0e0; font-size: 13px; outline: none;
  }
  .search-box::placeholder { color: #6b7a99; }
  .live-badge {
    margin-left: auto; font-size: 11px; background: #0d7377;
    color: #14ffec; padding: 3px 10px; border-radius: 10px;
  }

  /* ── 主体 ── */
  .main { display: flex; flex: 1; overflow: hidden; }

  /* ── 左侧客户列表 ── */
  .sidebar {
    width: 280px; background: #16213e;
    border-right: 1px solid #0f3460;
    display: flex; flex-direction: column; flex-shrink: 0;
  }
  .sidebar-header {
    padding: 10px 14px; font-size: 12px; color: #6b7a99;
    border-bottom: 1px solid #0f3460; flex-shrink: 0;
    display: flex; justify-content: space-between;
  }
  .customer-list { overflow-y: auto; flex: 1; }
  .customer-item {
    padding: 12px 14px; cursor: pointer; border-bottom: 1px solid #0f3460;
    transition: background .15s; position: relative;
  }
  .customer-item:hover { background: #1e3a5f; }
  .customer-item.active { background: #0f3460; border-left: 3px solid #4cc9f0; }
  .customer-item .name { font-size: 13px; font-weight: 500; color: #cce; }
  .customer-item .cid  { font-size: 11px; color: #6b7a99; margin-top: 2px; }
  .customer-item .meta { font-size: 11px; color: #8899aa; margin-top: 4px;
                         display: flex; justify-content: space-between; }
  .badge-plat {
    font-size: 10px; padding: 1px 6px; border-radius: 8px;
    background: #1a3a5c; color: #4cc9f0;
  }
  .badge-plat.ali   { background: #3d1a00; color: #ff9f43; }
  .badge-plat.email { background: #0a2e1a; color: #55efc4; }

  /* ── 右侧对话区 ── */
  .chat-panel {
    flex: 1; display: flex; flex-direction: column; overflow: hidden;
  }
  .chat-header {
    padding: 12px 20px; background: #16213e;
    border-bottom: 1px solid #0f3460; flex-shrink: 0;
    display: flex; align-items: center; gap: 10px;
  }
  .chat-header .cname { font-size: 15px; font-weight: 600; color: #e0e0e0; }
  .chat-header .cid   { font-size: 12px; color: #6b7a99; }
  .chat-header .stats { margin-left: auto; font-size: 12px; color: #6b7a99; }

  .chat-messages {
    flex: 1; overflow-y: auto; padding: 20px;
    display: flex; flex-direction: column; gap: 12px;
  }
  .day-divider {
    text-align: center; font-size: 11px; color: #6b7a99;
    position: relative; margin: 8px 0;
  }
  .day-divider::before, .day-divider::after {
    content: ""; position: absolute; top: 50%;
    width: 38%; height: 1px; background: #0f3460;
  }
  .day-divider::before { left: 0; }
  .day-divider::after  { right: 0; }

  /* 消息气泡 */
  .msg-row { display: flex; align-items: flex-end; gap: 8px; max-width: 72%; }
  .msg-row.in  { align-self: flex-start; }
  .msg-row.out { align-self: flex-end; flex-direction: row-reverse; }

  .avatar {
    width: 34px; height: 34px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 600; flex-shrink: 0;
  }
  .avatar.buyer  { background: #2d4a7a; color: #90caf9; }
  .avatar.seller { background: #1a6644; color: #a8e6cf; }

  .bubble-wrap { display: flex; flex-direction: column; gap: 3px; }
  .msg-row.out .bubble-wrap { align-items: flex-end; }

  .bubble {
    padding: 9px 13px; border-radius: 16px;
    font-size: 13px; line-height: 1.55; word-break: break-word;
    max-width: 480px;
  }
  .bubble.in  { background: #1e3a5f; color: #dce8f8; border-bottom-left-radius: 4px; }
  .bubble.out { background: #1a6644; color: #d4f5e7; border-bottom-right-radius: 4px; }
  .bubble img { max-width: 200px; border-radius: 8px; display: block; margin-top: 4px; }

  .msg-time { font-size: 10px; color: #6b7a99; padding: 0 4px; }

  /* 空状态 */
  .empty-state {
    flex: 1; display: flex; flex-direction: column;
    align-items: center; justify-content: center; color: #6b7a99; gap: 10px;
  }
  .empty-state .icon { font-size: 48px; opacity: .3; }
  .empty-state p { font-size: 14px; }

  /* 搜索结果覆盖层 */
  #search-overlay {
    display: none; position: absolute; top: 52px; left: 0; right: 0; bottom: 0;
    background: #1a1a2e; z-index: 10; overflow-y: auto; padding: 16px 20px;
  }
  .search-hit {
    padding: 10px 14px; margin-bottom: 8px;
    background: #16213e; border-radius: 10px; cursor: pointer;
    border-left: 3px solid #4cc9f0;
  }
  .search-hit:hover { background: #1e3a5f; }
  .search-hit .hit-cid  { font-size: 11px; color: #4cc9f0; }
  .search-hit .hit-msg  { font-size: 13px; color: #e0e0e0; margin-top: 4px; }
  .search-hit .hit-time { font-size: 11px; color: #6b7a99; margin-top: 3px; }
  mark { background: transparent; color: #f9ca24; font-weight: 600; }

  ::-webkit-scrollbar { width: 4px; }
  ::-webkit-scrollbar-thumb { background: #0f3460; border-radius: 2px; }
</style>
</head>
<body>

<div class="topbar">
  <h1>💬 聊天记录</h1>
  <input id="searchInput" class="search-box" placeholder="搜索消息内容..." autocomplete="off">
  <span class="live-badge" id="liveBadge">● 实时</span>
</div>

<div class="main" style="position:relative;">
  <!-- 搜索覆盖层 -->
  <div id="search-overlay"></div>

  <!-- 左侧客户列表 -->
  <div class="sidebar">
    <div class="sidebar-header">
      <span id="customerCount">客户</span>
      <span id="lastRefresh"></span>
    </div>
    <div class="customer-list" id="customerList"></div>
  </div>

  <!-- 右侧对话 -->
  <div class="chat-panel" id="chatPanel">
    <div class="empty-state" id="emptyState">
      <div class="icon">💬</div>
      <p>选择一位客户查看对话记录</p>
    </div>
    <div id="chatHeader" class="chat-header" style="display:none;">
      <div>
        <div class="cname" id="headerName"></div>
        <div class="cid" id="headerId"></div>
      </div>
      <div class="stats" id="headerStats"></div>
    </div>
    <div class="chat-messages" id="chatMessages" style="display:none;"></div>
  </div>
</div>

<script>
let currentCid = null;
let autoRefresh = null;
let allCustomers = [];

// ── 时间格式化 ──
function fmtTime(ts) {
  if (!ts) return '';
  const today = new Date().toISOString().slice(0,10);
  return ts.startsWith(today) ? ts.slice(11,16) : ts.slice(5,16);
}

// ── 平台徽章 ──
function platBadge(p) {
  const map = {
    AliWorkbench: ['ali','淘宝'],
    taobao:       ['ali','淘宝'],
    pinduoduo:    ['','拼多多'],
    jd:           ['','京东'],
    email:        ['email','邮件'],
  };
  const [cls, label] = map[p] || ['', p || ''];
  return label ? `<span class="badge-plat ${cls}">${label}</span>` : '';
}

// ── 加载客户列表 ──
async function loadCustomers() {
  const r = await fetch('/api/customers');
  allCustomers = await r.json();
  renderCustomers(allCustomers);
  document.getElementById('customerCount').textContent = `客户 ${allCustomers.length} 人`;
  document.getElementById('lastRefresh').textContent = new Date().toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'});
}

function renderCustomers(list) {
  const el = document.getElementById('customerList');
  el.innerHTML = list.map(c => {
    const active = c.customer_id === currentCid ? 'active' : '';
    const name = c.customer_name || c.customer_id.slice(-8);
    return `<div class="customer-item ${active}" onclick="openChat('${c.customer_id}','${(c.customer_name||'').replace(/'/g,"\\'")}','${c.platform||''}',${c.total_msgs},${c.recv},${c.sent})">
      <div class="name">${name} ${platBadge(c.platform)}</div>
      <div class="cid">${c.customer_id}</div>
      <div class="meta"><span>${c.total_msgs} 条消息</span><span>${fmtTime(c.last_time)}</span></div>
    </div>`;
  }).join('');
}

// ── 打开对话 ──
async function openChat(cid, name, platform, total, recv, sent) {
  currentCid = cid;
  renderCustomers(allCustomers);

  document.getElementById('emptyState').style.display = 'none';
  document.getElementById('chatHeader').style.display = 'flex';
  document.getElementById('chatMessages').style.display = 'flex';
  document.getElementById('headerName').textContent = name || cid;
  document.getElementById('headerId').textContent = cid;
  document.getElementById('headerStats').textContent = `共 ${total} 条  收 ${recv} 发 ${sent}`;

  await loadConversation(cid);
  if (autoRefresh) clearInterval(autoRefresh);
  autoRefresh = setInterval(() => loadConversation(cid), 4000);
}

// ── 加载对话 ──
async function loadConversation(cid) {
  const r = await fetch(`/api/conversation/${encodeURIComponent(cid)}`);
  const msgs = await r.json();
  renderMessages(msgs);
}

function renderMessages(msgs) {
  const el = document.getElementById('chatMessages');
  const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 60;

  let lastDate = '';
  const html = msgs.map(m => {
    const date = (m.timestamp || '').slice(0,10);
    let divider = '';
    if (date && date !== lastDate) { divider = `<div class="day-divider">${date}</div>`; lastDate = date; }

    const dir = m.direction;
    const avatarChar = dir === 'in' ? '买' : '客';
    const avatarCls  = dir === 'in' ? 'buyer' : 'seller';
    const content = renderMsgContent(m.message, m.msg_type);

    return `${divider}
    <div class="msg-row ${dir}">
      <div class="avatar ${avatarCls}">${avatarChar}</div>
      <div class="bubble-wrap">
        <div class="bubble ${dir}">${content}</div>
        <div class="msg-time">${fmtTime(m.timestamp)}</div>
      </div>
    </div>`;
  }).join('');

  el.innerHTML = html;
  if (atBottom) el.scrollTop = el.scrollHeight;
}

function renderMsgContent(msg, msgType) {
  if (!msg) return '';
  const urlRegGlobal = /(https?:\/\/[^\s]+?\.(jpg|jpeg|png|gif|webp)(\?[^\s]*)?)/gi;
  const urlRegSingle = /(https?:\/\/[^\s]+?\.(jpg|jpeg|png|gif|webp)(\?[^\s]*)?)/i;
  const parts = msg.split('#*#').map(s => s.trim()).filter(Boolean);
  if (parts.length > 1) {
    const segs = parts.map(p => {
      const m = p.match(urlRegSingle);
      if (m) {
        const url = m[0];
        return `<a href="${url}" target="_blank"><img src="${url}" onerror="this.style.display='none'"></a>`;
      }
      const esc = p.replace(/</g,'&lt;').replace(/>/g,'&gt;');
      return esc;
    });
    return segs.join('<br>');
  }
  const escaped = msg.replace(/</g,'&lt;').replace(/>/g,'&gt;');
  return escaped.replace(urlRegGlobal, (url) =>
    `<a href="${url}" target="_blank"><img src="${url}" onerror="this.style.display='none'"></a>`
  );
}

// ── 搜索 ──
let searchTimer = null;
document.getElementById('searchInput').addEventListener('input', function() {
  clearTimeout(searchTimer);
  const kw = this.value.trim();
  if (!kw) { closeSearch(); return; }
  searchTimer = setTimeout(() => doSearch(kw), 300);
});

async function doSearch(kw) {
  const r = await fetch(`/api/search?q=${encodeURIComponent(kw)}`);
  const results = await r.json();
  const overlay = document.getElementById('search-overlay');
  overlay.style.display = 'block';

  if (!results.length) {
    overlay.innerHTML = `<p style="color:#6b7a99;text-align:center;margin-top:60px;">未找到匹配消息</p>`;
    return;
  }
  const hi = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  const re = new RegExp(hi, 'gi');
  overlay.innerHTML = results.map(r => {
    const dir  = r.direction === 'in' ? '买家' : '客服';
    const msg  = r.message.replace(/</g,'&lt;').replace(re, m => `<mark>${m}</mark>`);
    return `<div class="search-hit" onclick="closeSearch(); openChat('${r.customer_id}','','','','','')">
      <div class="hit-cid">${r.customer_id}  ${r.customer_name||''} · ${dir}</div>
      <div class="hit-msg">${msg}</div>
      <div class="hit-time">${(r.timestamp||'').slice(0,16)}</div>
    </div>`;
  }).join('');
}

function closeSearch() {
  document.getElementById('search-overlay').style.display = 'none';
  document.getElementById('searchInput').value = '';
}

// ── 初始化 ──
loadCustomers();
setInterval(loadCustomers, 10000);
</script>
</body>
</html>
"""

PRICING_HTML = r"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 报价测试</title>
<style>
  body { font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
         background: #1a1a2e; color: #e0e0e0; padding: 20px; }
  .card { background:#16213e; border:1px solid #0f3460; border-radius:12px; padding:16px; max-width:880px; margin:0 auto; }
  .title { font-size:16px; color:#4cc9f0; margin-bottom:12px; }
  .row { display:flex; gap:12px; margin-bottom:10px; }
  .row .col { flex:1; }
  .input { width:100%; background:#0f3460; border:1px solid #1a5276; border-radius:10px; padding:10px 12px; color:#e0e0e0; font-size:13px; outline:none; }
  .input::placeholder { color:#6b7a99; }
  .btn { background:#0d7377; color:#14ffec; border:none; border-radius:10px; padding:10px 16px; cursor:pointer; font-size:13px; }
  .btn:disabled { opacity:.5; cursor:not-allowed; }
  .result { margin-top:14px; background:#0f3460; border:1px solid #1a5276; border-radius:10px; padding:12px; font-size:13px; white-space:pre-wrap; }
  .tip { font-size:12px; color:#6b7a99; margin-top:6px; }
</style>
</head>
<body>
  <div class="card">
    <div class="title">🧪 AI 报价测试</div>
    <div class="row">
      <div class="col">
        <input id="cid" class="input" placeholder="客户ID，如 tb7518056865:小林">
      </div>
      <div class="col">
        <input id="acc" class="input" placeholder="店铺ID（可留空）">
      </div>
    </div>
    <div class="row">
      <div class="col">
        <textarea id="msg" class="input" rows="4" placeholder="输入消息文本或图片URL（多张用 #*# 分隔）。示例：这两张有原图吗#*#https://...jpg#*#https://...png"></textarea>
      </div>
    </div>
    <div class="row">
      <button class="btn" id="runBtn" onclick="runPricing()">测试报价</button>
    </div>
    <div id="result" class="result" style="display:none;"></div>
    <div class="tip">提示：含图片URL时，Agent会自动调用图片分析并结合复杂度、尺寸、人脸与风险给出建议价；文本砍价低于最近图片底线会被礼貌拒绝。</div>
  </div>

<script>
async function runPricing() {
  const cid = document.getElementById('cid').value.trim();
  const acc = document.getElementById('acc').value.trim();
  const msg = document.getElementById('msg').value.trim();
  const btn = document.getElementById('runBtn');
  const res = document.getElementById('result');
  if (!cid || !msg) { alert('请填写客户ID与消息'); return; }
  btn.disabled = true; res.style.display = 'none'; res.textContent = '';
  try {
    const r = await fetch('/api/pricing/run', {
      method: 'POST',
      headers: {'Content-Type':'application/json'},
      body: JSON.stringify({ from_id: cid, acc_id: acc, msg })
    });
    const data = await r.json();
    res.style.display = 'block';
    res.textContent = data.error ? ('错误：'+data.error) : (
      `回复：${data.reply}\n\n【调试】目标Agent：${data.agent}\n最低价：${data.floor}\n应答：${data.should_reply?'是':'否'}`
    );
  } catch(e) {
    res.style.display = 'block';
    res.textContent = '请求失败：'+e;
  } finally {
    btn.disabled = false;
  }
}
</script>
</body>
</html>
"""


@app.route("/")
def index():
    return render_template_string(HTML)

@app.route("/pricing")
def pricing_index():
    return render_template_string(PRICING_HTML)


@app.route("/api/customers")
def api_customers():
    return jsonify(db.get_customers(limit=200))


@app.route("/api/conversation/<customer_id>")
def api_conversation(customer_id):
    return jsonify(db.get_conversation(customer_id, limit=500))


@app.route("/api/search")
def api_search():
    kw = request.args.get("q", "").strip()
    if not kw:
        return jsonify([])
    return jsonify(db.search_messages(kw, limit=60))


if __name__ == "__main__":
    print("聊天记录 UI 启动中...")
    print("访问 → http://localhost:5678")
    app.run(host="0.0.0.0", port=5678, debug=False)

@app.route("/api/pricing/run", methods=["POST"])
def api_pricing_run():
    global pricing_agent
    if pricing_agent is None:
        return jsonify({"error":"报价Agent未初始化"})
    data = request.get_json(force=True) or {}
    from_id = (data.get("from_id") or "").strip()
    acc_id  = (data.get("acc_id") or "").strip()
    msg     = (data.get("msg") or "").strip()
    if not from_id or not msg:
        return jsonify({"error":"缺少参数 from_id 或 msg"})
    # 构造提示词：直接使用用户输入，保持与正式场景一致
    user_prompt = msg
    deps = AgentDeps(
        msg_id="pricing-test",
        acc_id=acc_id or "TEST_SHOP",
        from_id=from_id,
        platform="taobao"
    )
    try:
        # 强制使用报价Agent
        result = asyncio.run(pricing_agent.agent_pricing.run(user_prompt, deps=deps, message_history=[]))
        # 读取底线
        try:
            from config.config import MIN_PRICE_FLOOR
            st = pricing_agent._get_conversation_state(from_id)
            floor = st.last_min_price if isinstance(st.last_min_price,int) and st.last_min_price>0 else MIN_PRICE_FLOOR
        except Exception:
            floor = None
        return jsonify({
            "reply": result.output,
            "should_reply": True,
            "agent": "pricing",
            "floor": floor
        })
    except Exception as e:
        return jsonify({"error": str(e)})
