import { and, asc, desc, eq } from "drizzle-orm";
import { apiError, requirePortalProfile } from "../_auth";
import { ensureDefaultReminderRules } from "../../../db/portal";
import { auditLogs, dues, members, reminderRules, reminders } from "../../../db/schema";

function atMidnight(value: string) {
  return new Date(`${value.slice(0, 10)}T00:00:00.000Z`);
}

async function generateDueReminders(actorEmail: string) {
  const { db } = await requirePortalProfile(true);
  const rules = (await ensureDefaultReminderRules()).filter((rule) => rule.enabled);
  const unpaid = await db
    .select({ due: dues, member: members })
    .from(dues)
    .innerJoin(members, eq(dues.memberId, members.id))
    .orderBy(asc(dues.dueDate));
  const now = new Date();
  const generated: Array<typeof reminders.$inferSelect> = [];

  for (const row of unpaid.filter((item) => !["paid", "cancelled"].includes(item.due.status))) {
    const dueDate = atMidnight(row.due.dueDate);
    for (const rule of rules) {
      const trigger = new Date(dueDate);
      const direction = rule.triggerType === "before_due" ? -1 : 1;
      trigger.setUTCDate(trigger.getUTCDate() + direction * rule.daysOffset);
      if (now < trigger) continue;
      if (rule.audience === "overdue" && now <= dueDate) continue;
      const [existing] = await db
        .select({ id: reminders.id })
        .from(reminders)
        .where(and(eq(reminders.dueId, row.due.id), eq(reminders.ruleId, rule.id)))
        .limit(1);
      if (existing) continue;
      const subject = rule.triggerType === "before_due" ? `Rappel cotisation ${row.due.year}` : `Relance cotisation ${row.due.year}`;
      const [created] = await db
        .insert(reminders)
        .values({
          memberId: row.member.id,
          dueId: row.due.id,
          ruleId: rule.id,
          channel: rule.channel,
          status: rule.channel === "in_app" ? "sent" : "scheduled",
          scheduledAt: trigger.toISOString(),
          sentAt: rule.channel === "in_app" ? now.toISOString() : null,
          subject,
          message: `La cotisation ${row.due.year} du lot ${row.member.lotReference}, d’un montant de ${(row.due.amountCents / 100).toFixed(2)} €, reste à régulariser.`,
        })
        .returning();
      generated.push(created);
    }
  }
  if (generated.length) {
    await db.insert(auditLogs).values({ actorEmail, action: "reminders.generated", entityType: "reminder", detail: `${generated.length} relance(s) générée(s)` });
  }
  return generated;
}

export async function GET() {
  try {
    const { user, profile, db } = await requirePortalProfile();
    if (profile.role === "bureau") {
      await generateDueReminders(user.email);
      const rules = await ensureDefaultReminderRules();
      const queue = await db
        .select({
          id: reminders.id,
          subject: reminders.subject,
          message: reminders.message,
          channel: reminders.channel,
          status: reminders.status,
          scheduledAt: reminders.scheduledAt,
          sentAt: reminders.sentAt,
          lotReference: members.lotReference,
          firstName: members.firstName,
          lastName: members.lastName,
        })
        .from(reminders)
        .innerJoin(members, eq(reminders.memberId, members.id))
        .orderBy(desc(reminders.createdAt))
        .limit(100);
      return Response.json({ rules, reminders: queue });
    }
    const own = await db
      .select()
      .from(reminders)
      .where(and(eq(reminders.memberId, profile.id), eq(reminders.channel, "in_app")))
      .orderBy(desc(reminders.createdAt))
      .limit(20);
    return Response.json({ reminders: own });
  } catch (error) {
    return apiError(error);
  }
}

export async function POST(request: Request) {
  try {
    const { user, db } = await requirePortalProfile(true);
    const payload = (await request.json()) as Record<string, unknown>;
    if (payload.action === "run") {
      const generated = await generateDueReminders(user.email);
      return Response.json({ generated: generated.length });
    }
    if (payload.action === "defaults") {
      const rules = await ensureDefaultReminderRules();
      return Response.json({ rules });
    }
    if (payload.action === "toggle") {
      const id = Number(payload.id);
      const enabled = Boolean(payload.enabled);
      const [rule] = await db.update(reminderRules).set({ enabled, updatedAt: new Date().toISOString() }).where(eq(reminderRules.id, id)).returning();
      if (!rule) return Response.json({ error: "Règle introuvable." }, { status: 404 });
      await db.insert(auditLogs).values({ actorEmail: user.email, action: "reminder_rule.updated", entityType: "reminder_rule", entityId: rule.id, detail: `${rule.label} · ${enabled ? "active" : "inactive"}` });
      return Response.json({ rule });
    }
    return Response.json({ error: "Action de relance inconnue." }, { status: 400 });
  } catch (error) {
    return apiError(error);
  }
}
