import fp from 'fastify-plugin';
import { asClass, Lifetime } from 'awilix';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod/v4';
import {
  CreateStoreSchema,
  UpdateStoreSchema,
  StoreQuerySchema,
  StoreResponseSchema,
  StoreListResponseSchema,
} from '@meshitrack/shared';
import { StoresRepository } from './stores.repository.js';
import { StoresService } from './stores.service.js';

type AnyStoreDoc = {
  _id: string | { toString: () => string };
  householdId: string;
  name: string;
  address?: string;
  location?: { lat: number; lng: number };
  url?: string;
  notes?: string;
  tags: string[];
  isActive: boolean;
  createdBy: string;
  createdAt: string | Date | { toISOString: () => string };
  updatedAt: string | Date | { toISOString: () => string };
};

function toIso(v: string | Date | { toISOString: () => string }): string {
  if (typeof v === 'string') return v;
  return v.toISOString();
}

function toStoreResponse(rawDoc: unknown) {
  const doc = rawDoc as AnyStoreDoc;
  return {
    _id: typeof doc._id === 'string' ? doc._id : doc._id.toString(),
    householdId: doc.householdId,
    name: doc.name,
    ...(doc.address != null ? { address: doc.address } : {}),
    ...(doc.location != null ? { location: doc.location } : {}),
    ...(doc.url != null ? { url: doc.url } : {}),
    ...(doc.notes != null ? { notes: doc.notes } : {}),
    tags: doc.tags,
    isActive: doc.isActive,
    createdBy: doc.createdBy,
    createdAt: toIso(doc.createdAt),
    updatedAt: toIso(doc.updatedAt),
  };
}

declare module '@fastify/awilix' {
  interface Cradle {
    storesRepository: StoresRepository;
    storesService: StoresService;
  }
}

export default fp(
  async (fastify) => {
    fastify.diContainer.register({
      storesRepository: asClass(StoresRepository, { lifetime: Lifetime.SINGLETON }),
      storesService: asClass(StoresService, { lifetime: Lifetime.SINGLETON }),
    });

    const app = fastify.withTypeProvider<ZodTypeProvider>();
    const householdParams = z.object({ householdId: z.string() });

    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/stores',
      schema: {
        params: householdParams,
        querystring: StoreQuerySchema,
        response: { 200: StoreListResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('storesService');
        const result = await service.list(request.params.householdId, request.query);
        return reply.send({
          data: result.data.map(toStoreResponse),
          pagination: result.pagination,
        });
      },
    });

    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/stores/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        response: { 200: StoreResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('storesService');
        const store = await service.getById(request.params.id, request.params.householdId);
        return reply.send(toStoreResponse(store));
      },
    });

    app.route({
      method: 'POST',
      url: '/api/v1/households/:householdId/stores',
      schema: {
        params: householdParams,
        body: CreateStoreSchema,
        response: { 201: StoreResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('storesService');
        const store = await service.create(
          request.body,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.status(201).send(toStoreResponse(store));
      },
    });

    app.route({
      method: 'PATCH',
      url: '/api/v1/households/:householdId/stores/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        body: UpdateStoreSchema,
        response: { 200: StoreResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('storesService');
        const store = await service.update(
          request.params.id,
          request.params.householdId,
          request.body,
        );
        return reply.send(toStoreResponse(store));
      },
    });

    app.route({
      method: 'DELETE',
      url: '/api/v1/households/:householdId/stores/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        response: { 200: StoreResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('storesService');
        const store = await service.deactivate(request.params.id, request.params.householdId);
        return reply.send(toStoreResponse(store));
      },
    });
  },
  {
    name: 'stores-routes',
    dependencies: ['auth-plugin'],
  },
);
