import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { eq, and } from 'drizzle-orm';
import { divisions, subDivisions } from '../../db/schema/index.js';

const divisionBody = z.object({
  name: z.string().min(1).max(100),
  displayOrder: z.number().int().default(0),
  metadata: z.record(z.string(), z.unknown()).default({}),
});

const subDivisionBody = z.object({
  name: z.string().min(1).max(100),
  shiftStart: z.string().nullable().optional(),
  shiftEnd: z.string().nullable().optional(),
  daysOfWeek: z.array(z.string()).nullable().optional(),
  capacity: z.number().int().positive().nullable().optional(),
  metadata: z.record(z.string(), z.unknown()).default({}),
});

export default async function academicRoutes(fastify: FastifyInstance) {
  const guard = [fastify.authenticate, fastify.authorize(['SUPER_ADMIN', 'SCHOOL_ADMIN'])];

  // ── Divisions ────────────────────────────────────────────────────────────────

  fastify.get('/divisions', { preHandler: [fastify.authenticate] }, async (request) => {
    const tenantId = request.user.tenantId!;
    const divRows = await fastify.db.select().from(divisions)
      .where(eq(divisions.tenantId, tenantId)).orderBy(divisions.displayOrder);
    const subRows = await fastify.db.select().from(subDivisions)
      .where(eq(subDivisions.tenantId, tenantId)).orderBy(subDivisions.name);

    return divRows.map((d) => ({
      ...d,
      subDivisions: subRows.filter((s) => s.divisionId === d.id),
    }));
  });

  fastify.post('/divisions', { preHandler: guard }, async (request, reply) => {
    const body = divisionBody.parse(request.body);
    const tenantId = request.user.tenantId!;
    const [row] = await fastify.db.insert(divisions).values({ ...body, tenantId }).returning();
    return reply.code(201).send(row);
  });

  fastify.patch('/divisions/:id', { preHandler: guard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const body = divisionBody.partial().parse(request.body);
    const tenantId = request.user.tenantId!;

    const [updated] = await fastify.db
      .update(divisions)
      .set({ ...body, updatedAt: new Date() })
      .where(and(eq(divisions.id, id), eq(divisions.tenantId, tenantId)))
      .returning();

    if (!updated) return reply.code(404).send({ error: 'Division not found' });
    return updated;
  });

  fastify.delete('/divisions/:id', { preHandler: guard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.user.tenantId!;
    const [deleted] = await fastify.db
      .delete(divisions)
      .where(and(eq(divisions.id, id), eq(divisions.tenantId, tenantId)))
      .returning({ id: divisions.id });

    if (!deleted) return reply.code(404).send({ error: 'Division not found' });
    return reply.code(204).send();
  });

  // ── Sub-Divisions ────────────────────────────────────────────────────────────

  fastify.post('/divisions/:divisionId/sub-divisions', { preHandler: guard }, async (request, reply) => {
    const { divisionId } = request.params as { divisionId: string };
    const body = subDivisionBody.parse(request.body);
    const tenantId = request.user.tenantId!;

    const [parent] = await fastify.db.select({ id: divisions.id }).from(divisions)
      .where(and(eq(divisions.id, divisionId), eq(divisions.tenantId, tenantId))).limit(1);
    if (!parent) return reply.code(404).send({ error: 'Division not found' });

    const [row] = await fastify.db.insert(subDivisions).values({ ...body, divisionId, tenantId }).returning();
    return reply.code(201).send(row);
  });

  fastify.patch('/sub-divisions/:id', { preHandler: guard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const body = subDivisionBody.partial().parse(request.body);
    const tenantId = request.user.tenantId!;

    const [updated] = await fastify.db
      .update(subDivisions)
      .set({ ...body, updatedAt: new Date() })
      .where(and(eq(subDivisions.id, id), eq(subDivisions.tenantId, tenantId)))
      .returning();

    if (!updated) return reply.code(404).send({ error: 'Sub-division not found' });
    return updated;
  });

  fastify.delete('/sub-divisions/:id', { preHandler: guard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.user.tenantId!;
    const [deleted] = await fastify.db
      .delete(subDivisions)
      .where(and(eq(subDivisions.id, id), eq(subDivisions.tenantId, tenantId)))
      .returning({ id: subDivisions.id });

    if (!deleted) return reply.code(404).send({ error: 'Sub-division not found' });
    return reply.code(204).send();
  });
}
