/**
 * Conversation store — MySQL-backed, tenant-scoped. Messages use the
 * auto-increment `seq` as a global monotonic cursor so widget/admin can poll
 * for "everything after seq N". All functions are async.
 *
 * Roles: user | assistant (AI) | agent (human admin) | system (status notes)
 */
import crypto from "node:crypto";
import { query } from "./db.js";

function rowToConversation(r) {
  if (!r) return null;
  return {
    id: r.id,
    tenantId: r.tenant_id,
    name: r.name,
    email: r.email,
    mode: r.mode,
    status: r.status,
    handoffRequested: !!r.handoff_requested,
    previousResponseId: r.previous_response_id,
    agentUnread: r.agent_unread,
    createdAt: r.created_at,
    updatedAt: r.updated_at,
  };
}

export async function createConversation(tenantId, name, email) {
  const id = crypto.randomUUID();
  const now = Date.now();
  await query(
    `INSERT INTO conversations (id, tenant_id, name, email, created_at, updated_at)
     VALUES (:id, :tenantId, :name, :email, :now, :now)`,
    { id, tenantId, name, email, now }
  );
  return { id, tenantId, name, email, mode: "ai", status: "open", handoffRequested: false, previousResponseId: null, agentUnread: 0, createdAt: now, updatedAt: now };
}

export async function getConversation(id) {
  const rows = await query("SELECT * FROM conversations WHERE id = :id", { id });
  return rowToConversation(rows[0]);
}

export async function addMessage(conversationId, role, text) {
  const conv = await getConversation(conversationId);
  if (!conv) return null;
  const id = crypto.randomUUID();
  const ts = Date.now();
  const res = await query(
    `INSERT INTO messages (id, conversation_id, tenant_id, role, text, ts)
     VALUES (:id, :cid, :tid, :role, :text, :ts)`,
    { id, cid: conversationId, tid: conv.tenantId, role, text, ts }
  );
  const seq = res.insertId;
  await query(
    `UPDATE conversations SET updated_at = :ts ${role === "user" ? ", agent_unread = agent_unread + 1" : ""} WHERE id = :cid`,
    { ts, cid: conversationId }
  );
  return { id, seq, role, text, ts };
}

export async function messagesAfter(conversationId, afterSeq, includeUser) {
  const rows = await query(
    `SELECT id, seq, role, text, ts FROM messages
     WHERE conversation_id = :cid AND seq > :after ${includeUser ? "" : "AND role <> 'user'"}
     ORDER BY seq ASC`,
    { cid: conversationId, after: afterSeq || 0 }
  );
  return rows;
}

export async function setPreviousResponseId(id, rid) {
  await query("UPDATE conversations SET previous_response_id = :rid WHERE id = :id", { rid, id });
}

export async function setMode(id, mode) {
  await query(
    `UPDATE conversations SET mode = :mode ${mode === "human" ? ", handoff_requested = 0" : ""} WHERE id = :id`,
    { mode, id }
  );
}

export async function requestHuman(id) {
  await query("UPDATE conversations SET handoff_requested = 1 WHERE id = :id", { id });
}

export async function setStatus(id, status) {
  await query("UPDATE conversations SET status = :status WHERE id = :id", { status, id });
}

export async function clearAgentUnread(id) {
  await query("UPDATE conversations SET agent_unread = 0 WHERE id = :id", { id });
}

/** List a tenant's conversations (most recent first) with their last message. */
export async function listConversations(tenantId) {
  const rows = await query(
    "SELECT * FROM conversations WHERE tenant_id = :tid ORDER BY updated_at DESC LIMIT 200",
    { tid: tenantId }
  );
  const out = [];
  for (const r of rows) {
    const c = rowToConversation(r);
    const last = await query(
      "SELECT id, seq, role, text, ts FROM messages WHERE conversation_id = :cid ORDER BY seq DESC LIMIT 1",
      { cid: c.id }
    );
    c.last = last[0] || null;
    out.push(c);
  }
  return out;
}

/** Full conversation with all messages (for the admin thread view). */
export async function getConversationWithMessages(id) {
  const conv = await getConversation(id);
  if (!conv) return null;
  conv.messages = await query(
    "SELECT id, seq, role, text, ts FROM messages WHERE conversation_id = :cid ORDER BY seq ASC",
    { cid: id }
  );
  return conv;
}
