import type { DatabaseSync } from "node:sqlite";
import { LocalMemoryProvider, MemoryManager } from "../memory/manager.ts";
import { BUSINESS_SCOPE, OWNER_SCOPE, WorkMemoryStore } from "../memory/store.ts";

export type AiToolName =
  | "ai_status"
  | "ai_models_list"
  | "ai_summarize_thread"
  | "ai_draft_reply"
  | "ai_rewrite_text"
  | "ai_transcribe_audio";

export type AiMemoryRequest = {
  tool: AiToolName;
  conversationId?: string | null;
  contactId?: string | null;
  baseSystemInstructions: string;
};

export type BuiltAiInstructions = {
  system_instructions: string;
  memory_snapshot: string;
  memory_scopes: string[];
  resolved_contact_id: string | null;
  memory_snapshot_semantics: string;
};

export function buildMemoryAwareInstructions(db: DatabaseSync, request: AiMemoryRequest): BuiltAiInstructions {
  const resolvedContactId = resolveAiContactId(db, request);
  const scopes = [BUSINESS_SCOPE, OWNER_SCOPE, ...(resolvedContactId ? [`contact:${resolvedContactId}`] : [])];
  const manager = new MemoryManager(new LocalMemoryProvider(new WorkMemoryStore(db)));
  const snapshot = manager.getSnapshot(scopes);
  return {
    system_instructions: snapshot ? `${snapshot}\n\n${request.baseSystemInstructions}` : request.baseSystemInstructions,
    memory_snapshot: snapshot,
    memory_scopes: scopes,
    resolved_contact_id: resolvedContactId,
    memory_snapshot_semantics: "Frozen per tool call: the snapshot is read once before generation/logging and later writes do not alter these instructions.",
  };
}

export function recordAiToolExchange(db: DatabaseSync, a: {
  tool: AiToolName;
  input?: unknown;
  response: unknown;
}) {
  const store = new WorkMemoryStore(db);
  const session = store.createSession({ source: a.tool }) as { id: string };
  store.addMessage({
    session_id: session.id,
    role: "user",
    content: JSON.stringify({ tool: a.tool, input: a.input ?? {} }),
  });
  store.addMessage({
    session_id: session.id,
    role: "assistant",
    content: JSON.stringify(a.response),
  });
  return session;
}

function resolveAiContactId(db: DatabaseSync, request: Pick<AiMemoryRequest, "conversationId" | "contactId">): string | null {
  const rawContact = request.contactId?.trim();
  if (rawContact && contactExists(db, rawContact)) return effectiveContactId(db, rawContact);

  const conversationId = request.conversationId?.trim();
  if (!conversationId) return null;
  const row = db.prepare(`
    SELECT contact_id
    FROM unified_conversation
    WHERE id=? AND deleted_at IS NULL
    LIMIT 1
  `).get(conversationId) as { contact_id?: string | null } | undefined;
  if (!row?.contact_id || !contactExists(db, row.contact_id)) return null;
  return effectiveContactId(db, row.contact_id);
}

function contactExists(db: DatabaseSync, contactId: string): boolean {
  const row = db.prepare(`SELECT 1 FROM contact WHERE id=? AND deleted_at IS NULL LIMIT 1`).get(contactId);
  return !!row;
}

function effectiveContactId(db: DatabaseSync, contactId: string): string {
  let current = contactId;
  for (let i = 0; i < 10; i++) {
    const row = db.prepare(`
      SELECT primary_contact_id
      FROM contact_merge
      WHERE merged_contact_id=? AND undone_at IS NULL
      LIMIT 1
    `).get(current) as { primary_contact_id?: string | null } | undefined;
    if (!row?.primary_contact_id) break;
    current = row.primary_contact_id;
  }
  return current;
}
