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

const createUserBody = z.object({
  username: z.string().min(2).max(50),
  email: z.string().email(),
  password: z.string().min(8),
  role: z.enum(['SCHOOL_ADMIN', 'TEACHER', 'RECEPTION']),
});

const updateUserBody = z.object({
  username: z.string().min(2).max(50).optional(),
  role: z.enum(['SCHOOL_ADMIN', 'TEACHER', 'RECEPTION']).optional(),
  status: z.enum(['ACTIVE', 'INACTIVE']).optional(),
  password: z.string().min(8).optional(),
});

function tenantFilter(request: { user: { tenantId: string | null; role: string } }) {
  return request.user.role === 'SUPER_ADMIN' ? undefined : request.user.tenantId!;
}

export default async function userRoutes(fastify: FastifyInstance) {
  fastify.get('/', { preHandler: [fastify.authenticate] }, async (request) => {
    const tenantId = tenantFilter(request);
    const query = fastify.db.select({
      id: users.id, tenantId: users.tenantId, username: users.username,
      email: users.email, role: users.role, status: users.status, createdAt: users.createdAt,
    }).from(users);

    if (tenantId) {
      return query.where(eq(users.tenantId, tenantId));
    }
    return query;
  });

  fastify.post('/', { preHandler: [fastify.authenticate, fastify.authorize(['SUPER_ADMIN', 'SCHOOL_ADMIN'])] }, async (request, reply) => {
    const body = createUserBody.parse(request.body);
    const tenantId = request.user.role === 'SUPER_ADMIN'
      ? (request.body as { tenantId?: string }).tenantId ?? null
      : request.user.tenantId;

    const passwordHash = await bcrypt.hash(body.password, 12);
    const [user] = await fastify.db
      .insert(users)
      .values({ ...body, passwordHash, tenantId })
      .returning({ id: users.id, tenantId: users.tenantId, username: users.username, email: users.email, role: users.role });

    return reply.code(201).send(user);
  });

  fastify.patch('/:id', { preHandler: [fastify.authenticate, fastify.authorize(['SUPER_ADMIN', 'SCHOOL_ADMIN'])] }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const body = updateUserBody.parse(request.body);
    const tenantId = tenantFilter(request);

    const updates: Record<string, unknown> = { ...body, updatedAt: new Date() };
    if (body.password) {
      updates['passwordHash'] = await bcrypt.hash(body.password, 12);
      delete updates['password'];
    }

    const condition = tenantId
      ? and(eq(users.id, id), eq(users.tenantId, tenantId))
      : eq(users.id, id);

    const [updated] = await fastify.db.update(users).set(updates).where(condition).returning({
      id: users.id, tenantId: users.tenantId, username: users.username, email: users.email, role: users.role, status: users.status,
    });

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

  fastify.delete('/:id', { preHandler: [fastify.authenticate, fastify.authorize(['SUPER_ADMIN', 'SCHOOL_ADMIN'])] }, async (request, reply) => {
    const { id } = request.params as { id: string };
    const tenantId = tenantFilter(request);
    const condition = tenantId ? and(eq(users.id, id), eq(users.tenantId, tenantId)) : eq(users.id, id);

    const [deleted] = await fastify.db.delete(users).where(condition).returning({ id: users.id });
    if (!deleted) return reply.code(404).send({ error: 'User not found' });
    return reply.code(204).send();
  });
}
