/**
 * ZKTeco ADMS (Attendance Data Management System) HTTP push handler.
 *
 * ZKTeco devices send attendance records via HTTP POST with query params:
 *   SN=<serial_no>&table=ATTLOG&Stamp=<timestamp>
 * Body contains tab-separated records:
 *   <user_id>\t<datetime>\t<state>\t<type>\t<reserved>\t<workcode>
 *
 * Reference: ZKTeco ADMS protocol documentation
 */
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { eq, and } from 'drizzle-orm';
import { devices, students } from '../../db/schema/index.js';
import { processRawScan } from '../attendance/attendance.service.js';

export async function handleAdmsPush(
  fastify: FastifyInstance,
  request: FastifyRequest,
  reply: FastifyReply
) {
  const query = request.query as Record<string, string>;
  const serialNo = query['SN'];
  const table = query['table'] ?? 'ATTLOG';

  if (!serialNo) {
    return reply.code(400).send('ERROR: Missing SN');
  }

  // Only process attendance log pushes
  if (table !== 'ATTLOG') {
    return reply.send('OK');
  }

  // Find device by serial number
  const [device] = await fastify.db
    .select()
    .from(devices)
    .where(eq(devices.serialNo, serialNo))
    .limit(1);

  if (!device) {
    fastify.log.warn({ serialNo }, 'ADMS push from unknown device');
    return reply.code(403).send('ERROR: Device not registered');
  }

  // Update device last_seen
  await fastify.db
    .update(devices)
    .set({ status: 'ONLINE', lastSeen: new Date(), updatedAt: new Date() })
    .where(eq(devices.id, device.id));

  // Parse body: each line = one attendance record
  const body = (request.body as string) ?? '';
  const lines = body.split('\n').filter((l) => l.trim().length > 0);

  let processed = 0;
  const errors: string[] = [];

  for (const line of lines) {
    const parts = line.trim().split('\t');
    if (parts.length < 2) continue;

    const [userId, datetimeStr] = parts;
    if (!userId || !datetimeStr) continue;

    try {
      const scanTime = new Date(datetimeStr.replace(' ', 'T'));
      if (isNaN(scanTime.getTime())) {
        errors.push(`Invalid datetime: ${datetimeStr}`);
        continue;
      }

      // Look up student by biometric_id within device's tenant
      const [student] = await fastify.db
        .select()
        .from(students)
        .where(and(eq(students.tenantId, device.tenantId), eq(students.biometricId, userId)))
        .limit(1);

      if (!student) {
        errors.push(`Unknown biometric_id: ${userId}`);
        continue;
      }

      await processRawScan(fastify, {
        tenantId: device.tenantId,
        studentId: student.id,
        deviceId: device.id,
        scanTime,
      });

      processed++;
    } catch (err) {
      fastify.log.error({ err, line }, 'Error processing ADMS scan');
      errors.push(`Failed: ${line}`);
    }
  }

  fastify.log.info({ serialNo, processed, errors: errors.length }, 'ADMS push processed');

  // ZKTeco expects a specific response format
  return reply
    .header('Content-Type', 'text/plain')
    .send(`OK: ${processed} records processed`);
}
