import type { FastifyInstance, FastifyPluginAsync } from 'fastify';
import {
  createApartmentSchema,
  updateApartmentSchema,
} from '@house-plan-maker/shared';
import type {
  Apartment,
  ApartmentWithRooms,
  ApiResponse,
  ApiListResponse,
} from '@house-plan-maker/shared';

const apartmentRoutes: FastifyPluginAsync = async (fastify: FastifyInstance) => {
  const { prisma } = fastify;

  // GET /api/apartments
  fastify.get('/api/apartments', async (): Promise<ApiListResponse<Apartment>> => {
    const apartments = await prisma.apartment.findMany({
      orderBy: { updatedAt: 'desc' },
      include: { _count: { select: { rooms: true } } },
    });

    return {
      data: apartments.map((apt) => ({
        ...toApartmentResponse(apt),
        roomCount: apt._count.rooms,
      })),
    };
  });

  // POST /api/apartments
  fastify.post('/api/apartments', async (request, reply): Promise<ApiResponse<Apartment>> => {
    const input = createApartmentSchema.parse(request.body);

    const apartment = await prisma.apartment.create({
      data: {
        name: input.name,
        address: input.address ?? null,
        totalArea: input.totalArea ?? null,
      },
    });

    reply.status(201);
    return { data: toApartmentResponse(apartment) };
  });

  // GET /api/apartments/:id
  fastify.get<{ Params: { id: string } }>(
    '/api/apartments/:id',
    async (request, reply): Promise<ApiResponse<ApartmentWithRooms>> => {
      const apartment = await prisma.apartment.findUnique({
        where: { id: request.params.id },
        include: {
          rooms: {
            select: { id: true, name: true, order: true },
            orderBy: { order: 'asc' },
          },
        },
      });

      if (!apartment) {
        return reply.status(404).send({ error: 'Apartment not found', statusCode: 404 });
      }

      return {
        data: {
          ...toApartmentResponse(apartment),
          rooms: apartment.rooms,
        },
      };
    },
  );

  // PUT /api/apartments/:id
  fastify.put<{ Params: { id: string } }>(
    '/api/apartments/:id',
    async (request, reply): Promise<ApiResponse<Apartment>> => {
      const input = updateApartmentSchema.parse(request.body);

      const existing = await prisma.apartment.findUnique({
        where: { id: request.params.id },
      });

      if (!existing) {
        return reply.status(404).send({ error: 'Apartment not found', statusCode: 404 });
      }

      const apartment = await prisma.apartment.update({
        where: { id: request.params.id },
        data: {
          ...(input.name !== undefined && { name: input.name }),
          ...(input.address !== undefined && { address: input.address ?? null }),
          ...(input.totalArea !== undefined && { totalArea: input.totalArea ?? null }),
        },
      });

      return { data: toApartmentResponse(apartment) };
    },
  );

  // DELETE /api/apartments/:id
  fastify.delete<{ Params: { id: string } }>(
    '/api/apartments/:id',
    async (request, reply): Promise<void> => {
      const existing = await prisma.apartment.findUnique({
        where: { id: request.params.id },
      });

      if (!existing) {
        return reply.status(404).send({ error: 'Apartment not found', statusCode: 404 });
      }

      await prisma.apartment.delete({
        where: { id: request.params.id },
      });

      reply.status(204);
    },
  );
};

function toApartmentResponse(apartment: {
  id: string;
  name: string;
  address: string | null;
  totalArea: number | null;
  createdAt: Date;
  updatedAt: Date;
}): Apartment {
  return {
    id: apartment.id,
    name: apartment.name,
    address: apartment.address,
    totalArea: apartment.totalArea,
    createdAt: apartment.createdAt.toISOString(),
    updatedAt: apartment.updatedAt.toISOString(),
  };
}

export default apartmentRoutes;
