import { Router } from "express";
import { z } from "zod";

import { prisma } from "../db";
import { requireAuth, type AuthRequest } from "../middleware/auth";

export const reminderTaskRouter = Router();
reminderTaskRouter.use(requireAuth);

const recurrenceSchema = z.object({
  type: z.enum(["hourly", "daily", "weekly", "monthly", "yearly"]),
  interval: z.number().int().min(1).optional(),
  byWeekday: z.number().int().min(0).max(6).optional(),
  byMonthday: z.number().int().min(1).max(31).optional(),
  timezone: z.string().optional(),
});

const offsetSchema = z.object({
  offsetMinutes: z.number().int().min(0),
  channelInapp: z.boolean().optional(),
  channelBark: z.boolean().optional(),
});

const taskSchema = z.object({
  title: z.string().min(1),
  description: z.string().optional(),
  dueAt: z.string().datetime(),
  recipientIds: z.array(z.string().min(1)),
  recurrenceRule: recurrenceSchema.optional(),
  offsets: z.array(offsetSchema).optional(),
});

reminderTaskRouter.get("/", async (req: AuthRequest, res) => {
  const items = await prisma.reminderTask.findMany({
    where: { creatorId: req.userId! },
    include: { recipients: true, recurrenceRule: true },
    orderBy: { dueAt: "asc" },
  });
  const offsets = await prisma.reminderOffset.findMany({
    where: { targetType: "reminder_task", targetId: { in: items.map((item) => item.id) } },
  });
  const offsetsById = offsets.reduce<Record<string, typeof offsets>>((acc, offset) => {
    acc[offset.targetId] = acc[offset.targetId] ?? [];
    acc[offset.targetId].push(offset);
    return acc;
  }, {});
  const withOffsets = items.map((item) => ({
    ...item,
    offsets: offsetsById[item.id] ?? [],
  }));
  return res.json(withOffsets);
});

reminderTaskRouter.post("/", async (req: AuthRequest, res) => {
  const parsed = taskSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid payload" });
  }
  const { recurrenceRule, offsets = [], recipientIds, ...data } = parsed.data;

  const task = await prisma.$transaction(async (tx) => {
    const rule = recurrenceRule
      ? await tx.recurrenceRule.create({
          data: {
            type: recurrenceRule.type,
            interval: recurrenceRule.interval ?? 1,
            byWeekday: recurrenceRule.byWeekday,
            byMonthday: recurrenceRule.byMonthday,
            timezone: recurrenceRule.timezone ?? "Asia/Shanghai",
          },
        })
      : null;

    const created = await tx.reminderTask.create({
      data: {
        creatorId: req.userId!,
        title: data.title,
        description: data.description,
        dueAt: new Date(data.dueAt),
        recurrenceRuleId: rule?.id,
      },
    });

    await tx.reminderTaskRecipient.createMany({
      data: recipientIds.map((userId) => ({ taskId: created.id, userId })),
      skipDuplicates: true,
    });

    if (offsets.length > 0) {
      await tx.reminderOffset.createMany({
        data: offsets.map((offset) => ({
          targetType: "reminder_task",
          targetId: created.id,
          offsetMinutes: offset.offsetMinutes,
          channelInapp: offset.channelInapp ?? true,
          channelBark: offset.channelBark ?? false,
        })),
      });
    }

    return created;
  });

  return res.json(task);
});

reminderTaskRouter.get("/:id", async (req: AuthRequest, res) => {
  const task = await prisma.reminderTask.findFirst({
    where: { id: req.params.id, creatorId: req.userId! },
    include: { recipients: true, recurrenceRule: true },
  });
  if (!task) {
    return res.status(404).json({ error: "Not found" });
  }
  const offsets = await prisma.reminderOffset.findMany({
    where: { targetType: "reminder_task", targetId: task.id },
  });
  return res.json({ ...task, offsets });
});

reminderTaskRouter.put("/:id", async (req: AuthRequest, res) => {
  const parsed = taskSchema.safeParse(req.body);
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid payload" });
  }
  const { recurrenceRule, offsets = [], recipientIds, ...data } = parsed.data;

  const updated = await prisma.$transaction(async (tx) => {
    const existing = await tx.reminderTask.findFirst({
      where: { id: req.params.id, creatorId: req.userId! },
    });
    if (!existing) {
      throw new Error("Not found");
    }

    let recurrenceRuleId = existing.recurrenceRuleId;
    if (recurrenceRule) {
      if (recurrenceRuleId) {
        await tx.recurrenceRule.update({
          where: { id: recurrenceRuleId },
          data: {
            type: recurrenceRule.type,
            interval: recurrenceRule.interval ?? 1,
            byWeekday: recurrenceRule.byWeekday,
            byMonthday: recurrenceRule.byMonthday,
            timezone: recurrenceRule.timezone ?? "Asia/Shanghai",
          },
        });
      } else {
        const created = await tx.recurrenceRule.create({
          data: {
            type: recurrenceRule.type,
            interval: recurrenceRule.interval ?? 1,
            byWeekday: recurrenceRule.byWeekday,
            byMonthday: recurrenceRule.byMonthday,
            timezone: recurrenceRule.timezone ?? "Asia/Shanghai",
          },
        });
        recurrenceRuleId = created.id;
      }
    } else if (recurrenceRuleId) {
      await tx.recurrenceRule.delete({ where: { id: recurrenceRuleId } });
      recurrenceRuleId = null;
    }

    await tx.reminderTaskRecipient.deleteMany({ where: { taskId: existing.id } });
    await tx.reminderTaskRecipient.createMany({
      data: recipientIds.map((userId) => ({ taskId: existing.id, userId })),
      skipDuplicates: true,
    });

    await tx.reminderOffset.deleteMany({
      where: { targetType: "reminder_task", targetId: existing.id },
    });
    if (offsets.length > 0) {
      await tx.reminderOffset.createMany({
        data: offsets.map((offset) => ({
          targetType: "reminder_task",
          targetId: existing.id,
          offsetMinutes: offset.offsetMinutes,
          channelInapp: offset.channelInapp ?? true,
          channelBark: offset.channelBark ?? false,
        })),
      });
    }

    return tx.reminderTask.update({
      where: { id: existing.id },
      data: {
        title: data.title,
        description: data.description,
        dueAt: new Date(data.dueAt),
        recurrenceRuleId,
      },
    });
  });

  return res.json(updated);
});

reminderTaskRouter.delete("/:id", async (req: AuthRequest, res) => {
  const deleted = await prisma.reminderTask.deleteMany({
    where: { id: req.params.id, creatorId: req.userId! },
  });
  if (deleted.count === 0) {
    return res.status(404).json({ error: "Not found" });
  }
  await prisma.reminderOffset.deleteMany({
    where: { targetType: "reminder_task", targetId: req.params.id },
  });
  await prisma.reminderTaskRecipient.deleteMany({ where: { taskId: req.params.id } });
  return res.json({ ok: true });
});
