import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { eq, and } from 'drizzle-orm';
import { devices } from '../../db/schema/index.js';
import { handleAdmsPush } from './adms.handler.js';

const deviceBody = z.object({
  deviceName: z.string().min(1).max(100),
  deviceIp: z.string().optional(),
  devicePort: z.number().int().default(4370),
  deviceType: z.enum(['FINGERPRINT', 'RFID', 'FACE']),
  commMode: z.enum(['ADMS', 'ZKLIB']),
  location: z.string().optional(),
  serialNo: z.string().optional(),
});

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

  fastify.get('/', { preHandler: guard }, async (request) => {
    const tenantId = request.user.tenantId!;
    return fastify.db.select().from(devices).where(eq(devices.tenantId, tenantId)).orderBy(devices.deviceName);
  });

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

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

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

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

  fastify.delete('/:id', { preHandler: adminGuard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.user.tenantId!;
    const [deleted] = await fastify.db
      .delete(devices)
      .where(and(eq(devices.id, id), eq(devices.tenantId, tenantId)))
      .returning({ id: devices.id });
    if (!deleted) return reply.code(404).send({ error: 'Device not found' });
    return reply.code(204).send();
  });

  fastify.get('/:id/status', { preHandler: guard }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = request.user.tenantId!;
    const [device] = await fastify.db.select({
      id: devices.id, deviceName: devices.deviceName, status: devices.status, lastSeen: devices.lastSeen, commMode: devices.commMode,
    }).from(devices).where(and(eq(devices.id, id), eq(devices.tenantId, tenantId))).limit(1);

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

    const isOnline = device.lastSeen
      ? Date.now() - new Date(device.lastSeen).getTime() < 5 * 60 * 1000
      : false;

    return { ...device, isOnline };
  });

  // ZKTeco ADMS push endpoint — device authenticates by serial_no
  fastify.post('/adms/push', async (request, reply) => {
    return handleAdmsPush(fastify, request, reply);
  });
}
