import fp from 'fastify-plugin';
import { asClass, Lifetime } from 'awilix';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod/v4';
import {
  CabinetEventQuerySchema,
  CabinetEventListResponseSchema,
  SpendingSummaryQuerySchema,
  SpendingSummaryResponseSchema,
} from '@meshitrack/shared';
import { CabinetEventsRepository } from './cabinet-events.repository.js';
import { CabinetEventsService } from './cabinet-events.service.js';

type AnyCabinetEventDoc = {
  _id: string | { toString: () => string };
  householdId: string;
  userId: string;
  cabinetItemId: string;
  medicineId: string;
  medicineName: string;
  eventType: string;
  quantity: number;
  quantityBefore: number;
  quantityAfter: number;
  unitPrice?: number | null;
  totalPrice?: number | null;
  currency?: string | null;
  storeId?: string | null;
  storeName?: string | null;
  sourceType: string;
  sourceId?: string | null;
  reason?: string | null;
  notes?: string | null;
  createdAt: string | Date | { toISOString: () => string };
};

function toStr(v: string | { toString: () => string }): string {
  return typeof v === 'string' ? v : v.toString();
}

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

function toCabinetEventResponse(doc: AnyCabinetEventDoc) {
  return {
    _id: toStr(doc._id),
    householdId: doc.householdId,
    userId: doc.userId,
    cabinetItemId: doc.cabinetItemId,
    medicineId: doc.medicineId,
    medicineName: doc.medicineName,
    eventType: doc.eventType,
    quantity: doc.quantity,
    quantityBefore: doc.quantityBefore,
    quantityAfter: doc.quantityAfter,
    ...(doc.unitPrice != null ? { unitPrice: doc.unitPrice } : {}),
    ...(doc.totalPrice != null ? { totalPrice: doc.totalPrice } : {}),
    ...(doc.currency ? { currency: doc.currency } : {}),
    ...(doc.storeId ? { storeId: doc.storeId } : {}),
    ...(doc.storeName ? { storeName: doc.storeName } : {}),
    sourceType: doc.sourceType,
    ...(doc.sourceId ? { sourceId: doc.sourceId } : {}),
    ...(doc.reason ? { reason: doc.reason } : {}),
    ...(doc.notes ? { notes: doc.notes } : {}),
    createdAt: toIso(doc.createdAt),
  };
}

declare module '@fastify/awilix' {
  interface Cradle {
    cabinetEventsRepository: CabinetEventsRepository;
    cabinetEventsService: CabinetEventsService;
  }
}

export default fp(
  async (fastify) => {
    fastify.diContainer.register({
      cabinetEventsRepository: asClass(CabinetEventsRepository, { lifetime: Lifetime.SINGLETON }),
      cabinetEventsService: asClass(CabinetEventsService, { lifetime: Lifetime.SINGLETON }),
    });

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

    // GET /api/v1/households/:householdId/cabinet-events — list events
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/cabinet-events',
      schema: {
        params: householdParams,
        querystring: CabinetEventQuerySchema,
        response: { 200: CabinetEventListResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('cabinetEventsService');
        const result = await service.listEvents(request.params.householdId, request.query);
        return reply.send({
          data: result.data.map(toCabinetEventResponse),
          pagination: result.pagination,
        });
      },
    });

    // GET /api/v1/households/:householdId/cabinet-events/by-item/:cabinetItemId — events for one item
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/cabinet-events/by-item/:cabinetItemId',
      schema: {
        params: householdParams.extend({ cabinetItemId: z.string() }),
        querystring: z.object({
          cursor: z.string().optional(),
          limit: z.coerce.number().int().min(1).max(100).default(20),
        }),
        response: { 200: CabinetEventListResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('cabinetEventsService');
        const result = await service.getEventsByItem(
          request.params.householdId,
          request.params.cabinetItemId,
          request.query,
        );
        return reply.send({
          data: result.data.map(toCabinetEventResponse),
          pagination: result.pagination,
        });
      },
    });

    // GET /api/v1/households/:householdId/cabinet-events/spending-summary — spending analytics
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/cabinet-events/spending-summary',
      schema: {
        params: householdParams,
        querystring: SpendingSummaryQuerySchema,
        response: { 200: SpendingSummaryResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('cabinetEventsService');
        const summary = await service.getSpendingSummary(request.params.householdId, request.query);
        return reply.send(summary);
      },
    });
  },
  {
    name: 'cabinet-events-routes',
    dependencies: ['auth-plugin'],
  },
);
