import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";

const VALID_CHANNELS = new Set(["SMS", "EMAIL", "WHATSAPP"]);
const VALID_AUDIENCES = new Set(["ALL_STUDENTS", "BY_CLASS", "STUDENT", "ALL_STAFF", "STAFF"]);

interface Recipient {
  name: string;
  phone: string | null;
  email: string | null;
}

/**
 * Resolve the recipient list for an audience. Students are represented by
 * their guardian (guardian phone); staff by their own phone/email.
 */
async function resolveRecipients(
  institutionId: number,
  audience: string,
  classItemId: number | null,
  studentId: number | null,
  staffId: number | null
): Promise<Recipient[]> {
  if (audience === "ALL_STAFF") {
    const staff = await prisma.staff.findMany({
      where: { institutionId, status: "ACTIVE" },
      select: { name: true, phone: true, email: true },
    });
    return staff.map((s) => ({ name: s.name, phone: s.phone, email: s.email }));
  }

  if (audience === "STAFF") {
    const staff = await prisma.staff.findFirst({
      where: { institutionId, id: staffId ?? -1, status: "ACTIVE" },
      select: { name: true, phone: true, email: true },
    });
    return staff ? [{ name: staff.name, phone: staff.phone, email: staff.email }] : [];
  }

  // Student audiences → guardians
  const where: Record<string, unknown> = { institutionId, status: "ACTIVE" };
  if (audience === "BY_CLASS" && classItemId) where.classItemId = classItemId;
  if (audience === "STUDENT") where.id = studentId ?? -1;

  const students = await prisma.student.findMany({
    where: where as never,
    select: { name: true, guardianName: true, guardianPhone: true },
  });
  return students.map((s) => ({
    name: s.guardianName || s.name,
    phone: s.guardianPhone,
    email: null,
  }));
}

/** Broadcast history + channel stats. */
export async function GET() {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const [broadcasts, setting] = await Promise.all([
    prisma.broadcast.findMany({
      where: { institutionId: session.institutionId },
      orderBy: { createdAt: "desc" },
      take: 50,
      include: {
        classItem: { select: { name: true, nameBn: true } },
        student: { select: { name: true, guardianName: true } },
        staff: { select: { name: true } },
        sentBy: { select: { name: true } },
        _count: { select: { recipients: true } },
      },
    }),
    prisma.commSetting.findUnique({
      where: { institutionId: session.institutionId },
      select: { smsBalance: true },
    }),
  ]);

  const stats = { total: broadcasts.length, SMS: 0, EMAIL: 0, WHATSAPP: 0 };
  for (const b of broadcasts) {
    for (const ch of b.channels as string[]) {
      if (ch in stats) stats[ch as keyof typeof stats] += 1;
    }
  }

  return NextResponse.json({
    stats,
    smsBalance: setting?.smsBalance ?? 0,
    broadcasts: broadcasts.map((b) => ({
      id: b.id,
      channels: b.channels,
      audience: b.audience,
      className: b.classItem?.name ?? null,
      classNameBn: b.classItem?.nameBn ?? null,
      studentName: b.student?.guardianName ?? b.student?.name ?? null,
      staffName: b.staff?.name ?? null,
      subject: b.subject,
      body: b.body,
      recipientCount: b._count.recipients,
      status: b.status,
      sentBy: b.sentBy?.name ?? null,
      createdAt: b.createdAt,
    })),
  });
}

/** Compose + send (simulated) a broadcast via one or more channels. */
export async function POST(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    const channels: string[] = Array.isArray(body.channels)
      ? [
          ...new Set(
            (body.channels as unknown[]).filter((c) => VALID_CHANNELS.has(c as string)).map((c) => c as string)
          ),
        ]
      : [];
    const audience = String(body.audience ?? "");
    const text = String(body.body ?? "").trim();
    const subject = channels.includes("EMAIL") ? String(body.subject ?? "").trim() || null : null;

    if (channels.length === 0) return NextResponse.json({ error: "NO_CHANNEL" }, { status: 400 });
    if (!VALID_AUDIENCES.has(audience)) return NextResponse.json({ error: "Invalid audience" }, { status: 400 });
    if (!text) return NextResponse.json({ error: "Empty message" }, { status: 400 });

    const classItemId = audience === "BY_CLASS" ? Number(body.classItemId) || null : null;
    const studentId = audience === "STUDENT" ? Number(body.studentId) || null : null;
    const staffId = audience === "STAFF" ? Number(body.staffId) || null : null;

    if (audience === "BY_CLASS" && !classItemId) {
      return NextResponse.json({ error: "Class required" }, { status: 400 });
    }
    if (audience === "STUDENT" && !studentId) {
      return NextResponse.json({ error: "Student required" }, { status: 400 });
    }
    if (audience === "STAFF" && !staffId) {
      return NextResponse.json({ error: "Staff required" }, { status: 400 });
    }

    const recipients = await resolveRecipients(
      session.institutionId,
      audience,
      classItemId,
      studentId,
      staffId
    );
    if (recipients.length === 0) {
      return NextResponse.json({ error: "NO_RECIPIENTS" }, { status: 400 });
    }

    // SMS channel consumes the purchased SMS balance
    const usesSms = channels.includes("SMS");
    if (usesSms) {
      const setting = await prisma.commSetting.findUnique({
        where: { institutionId: session.institutionId },
        select: { smsBalance: true },
      });
      if ((setting?.smsBalance ?? 0) < recipients.length) {
        return NextResponse.json({ error: "SMS_LOW_BALANCE" }, { status: 409 });
      }
    }

    // Simulated delivery: one log row per recipient. Swap this block for a real
    // gateway (Twilio / SMTP / WhatsApp Cloud API) when credentials are added.
    const broadcast = await prisma.$transaction(async (tx) => {
      const created = await tx.broadcast.create({
        data: {
          institutionId: session.institutionId!,
          channels,
          audience: audience as never,
          classItemId,
          studentId,
          staffId,
          subject,
          body: text,
          recipientCount: recipients.length,
          status: "SENT",
          sentById: session.userId,
        },
      });
      await tx.broadcastRecipient.createMany({
        data: recipients.map((r) => ({
          institutionId: session.institutionId!,
          broadcastId: created.id,
          name: r.name,
          phone: r.phone,
          email: r.email,
          channels,
        })),
      });
      if (usesSms) {
        await tx.commSetting.update({
          where: { institutionId: session.institutionId! },
          data: { smsBalance: { decrement: recipients.length } },
        });
      }
      return created;
    });

    return NextResponse.json({ broadcast: { id: broadcast.id, recipientCount: recipients.length } });
  } catch {
    return NextResponse.json({ error: "Could not send notification" }, { status: 500 });
  }
}
