import { Hono } from "hono";
import { bodyLimit } from "hono/body-limit";
import { eq, inArray } from "drizzle-orm";
import type { AppDatabase, AuthEnv, createAuth } from "../auth";
import * as schema from "../db/schema";
import { HabitService } from "../habits/service";

export function createAccountRoutes(db: AppDatabase, auth: ReturnType<typeof createAuth>, now: () => number) {
  const app = new Hono<AuthEnv>();
  app.use("*", auth.requireAuth);
  app.get("/export", c => {
    const user = c.get("user");
    const service = new HabitService(db, user, now()); service.sync();
    const data = db.transaction(tx => {
      const owned = tx.select({ id: schema.habits.id }).from(schema.habits).where(eq(schema.habits.userId, user.id));
      const days = tx.select({ id: schema.habitDays.id }).from(schema.habitDays).where(inArray(schema.habitDays.habitId, owned));
      return {
        formatVersion: 1, exportedAt: new Date(now()).toISOString(),
        user: tx.select().from(schema.users).where(eq(schema.users.id, user.id)).get(),
        habits: tx.select().from(schema.habits).where(eq(schema.habits.userId, user.id)).all(),
        revisions: tx.select().from(schema.habitRevisions).where(inArray(schema.habitRevisions.habitId, owned)).all(),
        days: tx.select().from(schema.habitDays).where(inArray(schema.habitDays.habitId, owned)).all(),
        tasks: tx.select().from(schema.taskOccurrences).where(inArray(schema.taskOccurrences.dayId, days)).all(),
        progressEvents: tx.select().from(schema.progressEvents).where(inArray(schema.progressEvents.dayId, days)).all(),
        calendarSettings: tx.select().from(schema.habitCalendarSettings).where(inArray(schema.habitCalendarSettings.habitId, owned)).all(),
        charts: tx.select().from(schema.combinedCharts).where(eq(schema.combinedCharts.userId, user.id)).all(),
        discordDeliveries: tx.select().from(schema.discordDeliveries).where(eq(schema.discordDeliveries.userId, user.id)).all(),
      };
    });
    c.header("Content-Disposition", 'attachment; filename="minabot-export.json"');
    return c.json(data);
  });
  app.delete("/", auth.requireSameOrigin, bodyLimit({ maxSize: 1024 }), async c => {
    const body = await c.req.json().catch(() => null);
    if (body?.confirmation !== "DELETE") return c.json({ error: "Type DELETE to confirm account deletion." }, 422);
    const userId = c.get("user").id;
    db.transaction(tx => {
      const owned = tx.select({ id: schema.habits.id }).from(schema.habits).where(eq(schema.habits.userId, userId));
      const days = tx.select({ id: schema.habitDays.id }).from(schema.habitDays).where(inArray(schema.habitDays.habitId, owned));
      tx.delete(schema.progressEvents).where(inArray(schema.progressEvents.dayId, days)).run();
      tx.delete(schema.taskOccurrences).where(inArray(schema.taskOccurrences.dayId, days)).run();
      tx.delete(schema.habitDays).where(inArray(schema.habitDays.habitId, owned)).run();
      tx.delete(schema.habitRevisions).where(inArray(schema.habitRevisions.habitId, owned)).run();
      tx.delete(schema.habitCalendarSettings).where(inArray(schema.habitCalendarSettings.habitId, owned)).run();
      tx.delete(schema.combinedCharts).where(eq(schema.combinedCharts.userId, userId)).run();
      tx.delete(schema.habits).where(eq(schema.habits.userId, userId)).run();
      tx.delete(schema.users).where(eq(schema.users.id, userId)).run();
    });
    auth.clearSession(c);
    return c.body(null, 204);
  });
  return app;
}
