import { Router, type IRouter } from "express";
import { db, profilesTable, profilePhotosTable, bookingsTable, walletTransactionsTable, locationsTable, servicesTable, usersTable } from "@workspace/db";
import { eq, and, desc } from "drizzle-orm";
import { requireRole } from "../middlewares/auth";
import { UpdateMyProfileBody, AddMyPhotoBody, DeleteMyPhotoParams } from "@workspace/api-zod";
import { serializeProfile } from "../lib/profile";
import { getOrCreateWallet } from "../lib/wallet";

const router: IRouter = Router();

// All /me/* routes manage a model's own profile — restrict to model accounts.
const requireModel = requireRole("model");

async function getOwnProfile(userId: number) {
  const rows = await db.select().from(profilesTable).where(eq(profilesTable.userId, userId));
  // Prefer a non-rejected profile if multiple exist.
  return rows.find((p) => p.approvalStatus !== "rejected") ?? rows[0];
}

router.get("/me/profile", requireModel, async (req, res): Promise<void> => {
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.status(404).json({ error: "No profile" });
    return;
  }
  res.json(serializeProfile(profile));
});

router.patch("/me/profile", requireModel, async (req, res): Promise<void> => {
  const parsed = UpdateMyProfileBody.safeParse(req.body);
  if (!parsed.success) {
    res.status(400).json({ error: parsed.error.message });
    return;
  }
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.status(404).json({ error: "No profile" });
    return;
  }
  const [updated] = await db
    .update(profilesTable)
    .set(parsed.data)
    .where(eq(profilesTable.id, profile.id))
    .returning();
  res.json(serializeProfile(updated));
});

router.get("/me/earnings", requireModel, async (req, res): Promise<void> => {
  const userId = req.user!.id;
  const wallet = await getOrCreateWallet(userId);
  const profile = await getOwnProfile(userId);

  let completedBookings = 0;
  if (profile) {
    const completed = await db
      .select({ id: bookingsTable.id })
      .from(bookingsTable)
      .where(and(eq(bookingsTable.profileId, profile.id), eq(bookingsTable.status, "completed")));
    completedBookings = completed.length;
  }

  // Earnings come from the wallet ledger (90% credits on completed bookings).
  const earningTx = await db
    .select()
    .from(walletTransactionsTable)
    .where(and(eq(walletTransactionsTable.userId, userId), eq(walletTransactionsTable.type, "earning")))
    .orderBy(desc(walletTransactionsTable.createdAt));
  const totalEarnings = earningTx.reduce((sum, t) => sum + t.amount, 0);

  res.json({
    availableBalance: wallet.balance,
    totalEarnings,
    completedBookings,
    recent: earningTx.slice(0, 10),
  });
});

router.get("/me/orders", requireModel, async (req, res): Promise<void> => {
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.json([]);
    return;
  }
  const rows = await db.select({
    booking: bookingsTable,
    locationName: locationsTable.name,
    serviceName: servicesTable.name,
    customerName: usersTable.name,
  }).from(bookingsTable)
    .leftJoin(locationsTable, eq(bookingsTable.locationId, locationsTable.id))
    .leftJoin(servicesTable, eq(bookingsTable.serviceId, servicesTable.id))
    .leftJoin(usersTable, eq(bookingsTable.userId, usersTable.id))
    .where(eq(bookingsTable.profileId, profile.id))
    .orderBy(desc(bookingsTable.createdAt));

  res.json(rows.map(({ booking, locationName, serviceName, customerName }) => ({
    id: booking.id,
    userId: booking.userId,
    profileId: booking.profileId,
    locationId: booking.locationId,
    serviceId: booking.serviceId,
    profileName: profile.name,
    locationName,
    serviceName,
    customerName,
    duration: booking.duration,
    locationType: booking.locationType,
    totalPrice: booking.totalPrice,
    status: booking.status,
    notes: booking.notes,
    scheduledAt: booking.scheduledAt,
    createdAt: booking.createdAt,
  })));
});

router.get("/me/photos", requireModel, async (req, res): Promise<void> => {
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.json([]);
    return;
  }
  const photos = await db
    .select()
    .from(profilePhotosTable)
    .where(eq(profilePhotosTable.profileId, profile.id))
    .orderBy(profilePhotosTable.sortOrder, profilePhotosTable.id);
  res.json(photos);
});

router.post("/me/photos", requireModel, async (req, res): Promise<void> => {
  const parsed = AddMyPhotoBody.safeParse(req.body);
  if (!parsed.success) {
    res.status(400).json({ error: parsed.error.message });
    return;
  }
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.status(404).json({ error: "No profile" });
    return;
  }
  const [photo] = await db
    .insert(profilePhotosTable)
    .values({ profileId: profile.id, url: parsed.data.url, sortOrder: parsed.data.sortOrder ?? 0 })
    .returning();
  res.status(201).json(photo);
});

router.delete("/me/photos/:id", requireModel, async (req, res): Promise<void> => {
  const parsed = DeleteMyPhotoParams.safeParse({ id: req.params.id });
  if (!parsed.success) {
    res.status(400).json({ error: "Invalid ID" });
    return;
  }
  const profile = await getOwnProfile(req.user!.id);
  if (!profile) {
    res.sendStatus(204);
    return;
  }
  await db
    .delete(profilePhotosTable)
    .where(and(eq(profilePhotosTable.id, parsed.data.id), eq(profilePhotosTable.profileId, profile.id)));
  res.sendStatus(204);
});

export default router;
