/**
 * Tenant model. Tenants are created and managed by the platform super-admin
 * (no self-signup). Each tenant can configure its own OpenAI key, SMTP, admin
 * email, branding and system prompt. A tenant can be paused (widget disabled).
 */
import crypto from "node:crypto";
import bcrypt from "bcryptjs";
import { query } from "./db.js";
import { getClient } from "./openai.js";

const DEFAULT_SETTINGS = {
  assistantName: "Support",
  greeting: "Hi there! 👋 How can I help you today?",
  accentColor: "#6366f1",
  systemPrompt:
    "You are a friendly, professional customer-support assistant. Answer the visitor's questions accurately and concisely using the information available to you. When a specific page on the company's website is relevant, include its full URL so the visitor can go straight to it. If you don't know the answer, politely say you don't have that information and offer to connect them with a member of the team. IMPORTANT: never mention documents, files, PDFs, uploads, a knowledge base, or that your answers come from any source — just answer naturally as a support agent would.",
  openaiKey: "",
  notifyEmail: "",
  smtp: { host: "", port: 587, secure: false, user: "", pass: "", from: "" },
};

function rowToTenant(r) {
  if (!r) return null;
  let settings = {};
  try { settings = typeof r.settings === "string" ? JSON.parse(r.settings) : r.settings || {}; } catch {}
  return {
    id: r.id,
    publicKey: r.public_key,
    name: r.name,
    siteUrl: r.site_url,
    adminEmail: r.admin_email,
    passwordHash: r.password_hash,
    vectorStoreId: r.vector_store_id,
    status: r.status || "active",
    settings: { ...DEFAULT_SETTINGS, ...settings, smtp: { ...DEFAULT_SETTINGS.smtp, ...(settings.smtp || {}) } },
    createdAt: r.created_at,
  };
}

/** OpenAI client for a tenant (their key, or the platform key as fallback). */
export function clientFor(tenant) {
  return getClient(tenant.settings.openaiKey);
}

/** Effective SMTP config for a tenant (their SMTP, or null → env fallback). */
export function smtpFor(tenant) {
  const s = tenant.settings.smtp || {};
  return s.host ? s : null;
}

/** Notification/support email for a tenant (settings, or login email). */
export function notifyEmailFor(tenant) {
  return tenant.settings.notifyEmail || tenant.adminEmail;
}

export async function createTenant({ name, siteUrl, email, password, openaiKey }) {
  const existing = await query("SELECT id FROM tenants WHERE admin_email = :email", { email });
  if (existing.length) throw new Error("A tenant with that email already exists.");

  const publicKey = "wgt_" + crypto.randomBytes(16).toString("hex");
  const passwordHash = await bcrypt.hash(password, 10);
  const settings = { ...DEFAULT_SETTINGS, assistantName: name, openaiKey: openaiKey || "" };

  await query(
    `INSERT INTO tenants (public_key, name, site_url, admin_email, password_hash, vector_store_id, status, settings, created_at)
     VALUES (:publicKey, :name, :siteUrl, :email, :passwordHash, NULL, 'active', :settings, :now)`,
    { publicKey, name, siteUrl: siteUrl || null, email, passwordHash, settings: JSON.stringify(settings), now: Date.now() }
  );
  return getTenantByEmail(email);
}

/** Create the tenant's vector store on first use (needs a valid OpenAI key). */
export async function ensureVectorStore(tenant) {
  if (tenant.vectorStoreId) return tenant.vectorStoreId;
  const store = await clientFor(tenant).vectorStores.create({ name: `kb-${tenant.name}`.slice(0, 60) });
  await setVectorStoreId(tenant.id, store.id);
  tenant.vectorStoreId = store.id;
  return store.id;
}

export async function getTenantById(id) {
  const rows = await query("SELECT * FROM tenants WHERE id = :id", { id });
  return rowToTenant(rows[0]);
}
export async function getTenantByKey(publicKey) {
  const rows = await query("SELECT * FROM tenants WHERE public_key = :k", { k: publicKey });
  return rowToTenant(rows[0]);
}
export async function getTenantByEmail(email) {
  const rows = await query("SELECT * FROM tenants WHERE admin_email = :email", { email });
  return rowToTenant(rows[0]);
}

export async function authenticate(email, password) {
  const t = await getTenantByEmail(email);
  if (!t) return null;
  const ok = await bcrypt.compare(password, t.passwordHash);
  return ok ? t : null;
}

export async function updateSettings(id, patch) {
  const t = await getTenantById(id);
  if (!t) throw new Error("Tenant not found");
  const settings = { ...t.settings, ...patch };
  if (patch.smtp) settings.smtp = { ...t.settings.smtp, ...patch.smtp };
  await query("UPDATE tenants SET settings = :s WHERE id = :id", { s: JSON.stringify(settings), id });
  return settings;
}

export async function setVectorStoreId(id, vsid) {
  await query("UPDATE tenants SET vector_store_id = :v WHERE id = :id", { v: vsid, id });
}

export async function updatePassword(id, newPassword) {
  const passwordHash = await bcrypt.hash(newPassword, 10);
  await query("UPDATE tenants SET password_hash = :h WHERE id = :id", { h: passwordHash, id });
}

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

/** Super-admin edit of core fields (name/site/email; password if provided). */
export async function editTenant(id, { name, siteUrl, email, password }) {
  const sets = [], params = { id };
  if (typeof name === "string" && name.trim()) { sets.push("name = :name"); params.name = name.trim(); }
  if (typeof siteUrl === "string") { sets.push("site_url = :siteUrl"); params.siteUrl = siteUrl.trim() || null; }
  if (typeof email === "string" && email.trim()) { sets.push("admin_email = :email"); params.email = email.trim(); }
  if (typeof password === "string" && password) { sets.push("password_hash = :ph"); params.ph = await bcrypt.hash(password, 10); }
  if (sets.length) await query(`UPDATE tenants SET ${sets.join(", ")} WHERE id = :id`, params);
  return getTenantById(id);
}

/** All tenants with conversation counts (super-admin console). */
export async function listAllTenants() {
  const rows = await query(`
    SELECT t.id, t.public_key, t.name, t.site_url, t.admin_email, t.vector_store_id, t.status, t.settings, t.created_at,
           COUNT(c.id) AS conversation_count, MAX(c.updated_at) AS last_activity
    FROM tenants t LEFT JOIN conversations c ON c.tenant_id = t.id
    GROUP BY t.id ORDER BY t.created_at DESC
  `);
  return rows.map((r) => {
    let settings = {}; try { settings = typeof r.settings === "string" ? JSON.parse(r.settings) : r.settings || {}; } catch {}
    return {
      id: r.id, publicKey: r.public_key, name: r.name, siteUrl: r.site_url, adminEmail: r.admin_email,
      status: r.status || "active", hasOpenaiKey: Boolean(settings.openaiKey), createdAt: r.created_at,
      conversationCount: Number(r.conversation_count) || 0, lastActivity: r.last_activity ? Number(r.last_activity) : null,
    };
  });
}

export async function deleteTenant(id) {
  const t = await getTenantById(id);
  if (!t) return;
  if (t.vectorStoreId) { try { await clientFor(t).vectorStores.del(t.vectorStoreId); } catch {} }
  await query("DELETE FROM messages WHERE tenant_id = :id", { id });
  await query("DELETE FROM conversations WHERE tenant_id = :id", { id });
  await query("DELETE FROM tenants WHERE id = :id", { id });
}
