import fs from "node:fs/promises";
import fsSync from "node:fs";
import path from "node:path";
import { PrismaClient } from "@prisma/client";

function loadEnvFromDotEnv() {
  const p = path.resolve(process.cwd(), ".env");
  if (!fsSync.existsSync(p)) return;
  const raw = fsSync.readFileSync(p, "utf8");
  for (const line of raw.split("\n")) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith("#")) continue;
    const idx = trimmed.indexOf("=");
    if (idx === -1) continue;
    const key = trimmed.slice(0, idx).trim();
    let val = trimmed.slice(idx + 1).trim();
    if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
      val = val.slice(1, -1);
    }
    if (!key) continue;
    if (key === "DATABASE_URL") {
      process.env[key] = val;
      continue;
    }
    if (!process.env[key]) process.env[key] = val;
  }
}

loadEnvFromDotEnv();

const prisma = new PrismaClient();

function datasetRoot() {
  const teamId = process.env.TEAM_ID || "demo-team";
  const userId = process.env.USER_ID || "demo-user";
  return path.resolve(process.cwd(), "..", ".data", "crmfs", "teams", teamId, "users", userId);
}

async function ensureDir(p) {
  await fs.mkdir(p, { recursive: true });
}

async function writeJson(p, value) {
  await fs.writeFile(p, JSON.stringify(value, null, 2) + "\n", "utf8");
}

function jsonlLine(value) {
  return JSON.stringify(value) + "\n";
}

async function main() {
  const root = datasetRoot();
  const tmp = root + ".tmp";

  await fs.rm(tmp, { recursive: true, force: true });
  await ensureDir(tmp);

  const contactsDir = path.join(tmp, "contacts");
  const notesDir = path.join(tmp, "notes");
  const messagesDir = path.join(tmp, "messages");
  const eventsDir = path.join(tmp, "events");
  const indexDir = path.join(tmp, "index");
  await Promise.all([
    ensureDir(contactsDir),
    ensureDir(notesDir),
    ensureDir(messagesDir),
    ensureDir(eventsDir),
    ensureDir(indexDir),
  ]);

  const teamId = process.env.TEAM_ID || "demo-team";
  const contacts = await prisma.contact.findMany({
    where: { teamId },
    orderBy: { updatedAt: "desc" },
    include: {
      note: { select: { content: true, updatedAt: true } },
      messages: {
        select: {
          kind: true,
          direction: true,
          channel: true,
          content: true,
          durationSec: true,
          transcriptJson: true,
          occurredAt: true,
        },
        orderBy: { occurredAt: "asc" },
      },
      events: {
        select: { title: true, startsAt: true, endsAt: true, status: true, note: true },
        orderBy: { startsAt: "asc" },
      },
    },
    take: 5000,
  });

  const contactIndex = [];
  for (const c of contacts) {
    await writeJson(path.join(contactsDir, `${c.id}.json`), {
      id: c.id,
      teamId: c.teamId,
      name: c.name,
      company: c.company ?? null,
      country: c.country ?? null,
      location: c.location ?? null,
      avatarUrl: c.avatarUrl ?? null,
      email: c.email ?? null,
      phone: c.phone ?? null,
      createdAt: c.createdAt,
      updatedAt: c.updatedAt,
    });

    await fs.writeFile(
      path.join(notesDir, `${c.id}.md`),
      (c.note?.content?.trim() ? c.note.content.trim() : "") + "\n",
      "utf8",
    );

    await fs.writeFile(
      path.join(messagesDir, `${c.id}.jsonl`),
      c.messages
        .map((m) =>
          jsonlLine({
            kind: m.kind,
            direction: m.direction,
            channel: m.channel,
            occurredAt: m.occurredAt,
            content: m.content,
            durationSec: m.durationSec ?? null,
            transcript: m.transcriptJson ?? null,
          }),
        )
        .join(""),
      "utf8",
    );

    await fs.writeFile(
      path.join(eventsDir, `${c.id}.jsonl`),
      c.events
        .map((e) =>
          jsonlLine({
            title: e.title,
            startsAt: e.startsAt,
            endsAt: e.endsAt,
            status: e.status ?? null,
            note: e.note ?? null,
          }),
        )
        .join(""),
      "utf8",
    );

    const lastMessageAt = c.messages.length ? c.messages[c.messages.length - 1].occurredAt : null;
    const nextEventAt = c.events.find((e) => new Date(e.startsAt).getTime() >= Date.now())?.startsAt ?? null;
    contactIndex.push({
      id: c.id,
      name: c.name,
      company: c.company ?? null,
      lastMessageAt,
      nextEventAt,
      updatedAt: c.updatedAt,
    });
  }

  await writeJson(path.join(indexDir, "contacts.json"), contactIndex);
  await writeJson(path.join(tmp, "meta.json"), { exportedAt: new Date().toISOString(), version: 1 });

  await ensureDir(path.dirname(root));
  await fs.rm(root, { recursive: true, force: true });
  await fs.rename(tmp, root);

  console.log("exported", root);
}

await main()
  .catch((e) => {
    console.error(e);
    process.exitCode = 1;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
