import fp from 'fastify-plugin';
import { asClass, Lifetime } from 'awilix';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod/v4';
import {
  CreatePurchaseSchema,
  UpdatePurchaseSchema,
  PurchaseQuerySchema,
  PurchaseResponseSchema,
  PurchaseListResponseSchema,
} from '@meshitrack/shared';
import { PurchasesRepository } from './purchases.repository.js';
import { PurchasesService } from './purchases.service.js';

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

type AnyPurchaseItem = {
  _id?: string | { toString: () => string };
  medicineProductId?: string;
  medicineId?: string;
  foodProductId?: string;
  name: string;
  quantity: number;
  unit: string;
  actualPrice?: number;
  currency?: string;
  priceRecordId?: string;
  addedToCabinet: boolean;
};

type AnyPurchase = {
  _id: string | { toString: () => string };
  householdId: string;
  storeId: string;
  storeName: string;
  status: string;
  items: AnyPurchaseItem[];
  notes?: string;
  purchasedAt: Date | string | { toISOString: () => string };
  receivedAt?: Date | string | { toISOString: () => string };
  createdBy: string;
  createdAt: Date | string | { toISOString: () => string };
  updatedAt: Date | string | { toISOString: () => string };
};

function toItemResponse(item: AnyPurchaseItem) {
  return {
    _id: item._id ? (typeof item._id === 'string' ? item._id : item._id.toString()) : '',
    ...(item.medicineProductId ? { medicineProductId: item.medicineProductId } : {}),
    ...(item.medicineId ? { medicineId: item.medicineId } : {}),
    ...(item.foodProductId ? { foodProductId: item.foodProductId } : {}),
    name: item.name,
    quantity: item.quantity,
    unit: item.unit,
    ...(item.actualPrice != null ? { actualPrice: item.actualPrice } : {}),
    ...(item.currency ? { currency: item.currency } : {}),
    ...(item.priceRecordId ? { priceRecordId: item.priceRecordId } : {}),
    addedToCabinet: item.addedToCabinet,
  };
}

function toPurchaseResponse(doc: AnyPurchase) {
  return {
    _id: typeof doc._id === 'string' ? doc._id : doc._id.toString(),
    householdId: doc.householdId,
    storeId: doc.storeId,
    storeName: doc.storeName,
    status: doc.status as 'ordered' | 'in_cabinet',
    items: doc.items.map(toItemResponse),
    ...(doc.notes ? { notes: doc.notes } : {}),
    purchasedAt: toIso(doc.purchasedAt),
    ...(doc.receivedAt ? { receivedAt: toIso(doc.receivedAt) } : {}),
    createdBy: doc.createdBy,
    createdAt: toIso(doc.createdAt),
    updatedAt: toIso(doc.updatedAt),
  };
}

declare module '@fastify/awilix' {
  interface Cradle {
    purchasesRepository: PurchasesRepository;
    purchasesService: PurchasesService;
  }
}

export default fp(
  async (fastify) => {
    fastify.diContainer.register({
      purchasesRepository: asClass(PurchasesRepository, { lifetime: Lifetime.SINGLETON }),
      purchasesService: asClass(PurchasesService, { lifetime: Lifetime.SINGLETON }),
    });

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

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

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

    app.route({
      method: 'POST',
      url: '/api/v1/households/:householdId/purchases',
      schema: {
        params: householdParams,
        body: CreatePurchaseSchema,
        response: { 201: PurchaseResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('purchasesService');
        const purchase = await service.create(
          request.body,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.status(201).send(toPurchaseResponse(purchase));
      },
    });

    app.route({
      method: 'PATCH',
      url: '/api/v1/households/:householdId/purchases/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        body: UpdatePurchaseSchema,
        response: { 200: PurchaseResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('purchasesService');
        const purchase = await service.update(
          request.params.id,
          request.params.householdId,
          request.body,
        );
        return reply.send(toPurchaseResponse(purchase));
      },
    });

    app.route({
      method: 'POST',
      url: '/api/v1/households/:householdId/purchases/:id/receive',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        response: {
          200: z.object({
            addedCount: z.number(),
            priceRecordsCreated: z.number(),
          }),
        },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('purchasesService');
        const result = await service.receive(
          request.params.id,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.send(result);
      },
    });

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