import fp from 'fastify-plugin';
import { asClass, Lifetime } from 'awilix';
import type { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod/v4';
import {
  CreateRegimenSchema,
  UpdateRegimenSchema,
  RegimenQuerySchema,
  RegimenResponseSchema,
  RegimenListResponseSchema,
  BurnRateResponseSchema,
} from '@meshitrack/shared';
import { RegimensRepository } from './regimens.repository.js';
import { RegimensService } from './regimens.service.js';

type AnyRegimenMedication = {
  medicineId: string;
  medicineName: string;
  medicineStrength: number;
  medicineStrengthUnit: string;
  medicineForm: string;
  dosage: number;
  dosageUnit: string;
  frequency: string;
  customFrequencyPerDay?: number | null;
  timeOfDay?: string | null;
  instructions?: string | null;
};

type AnyRegimenDoc = {
  _id: string | { toString: () => string };
  householdId: string;
  userId: string;
  name: string;
  isActive: boolean;
  medications: AnyRegimenMedication[];
  createdBy: string;
  createdAt: string | { toISOString: () => string };
  updatedAt: string | { 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 toRegimenResponse(doc: AnyRegimenDoc) {
  return {
    _id: toStr(doc._id),
    householdId: doc.householdId,
    userId: doc.userId,
    name: doc.name,
    isActive: doc.isActive,
    medications: doc.medications.map((med) => ({
      medicineId: med.medicineId,
      medicineName: med.medicineName,
      medicineStrength: med.medicineStrength,
      medicineStrengthUnit: med.medicineStrengthUnit,
      medicineForm: med.medicineForm,
      dosage: med.dosage,
      dosageUnit: med.dosageUnit,
      frequency: med.frequency,
      ...(med.customFrequencyPerDay != null
        ? { customFrequencyPerDay: med.customFrequencyPerDay }
        : {}),
      ...(med.timeOfDay ? { timeOfDay: med.timeOfDay } : {}),
      ...(med.instructions ? { instructions: med.instructions } : {}),
    })),
    createdBy: doc.createdBy,
    createdAt: toIso(doc.createdAt),
    updatedAt: toIso(doc.updatedAt),
  };
}

declare module '@fastify/awilix' {
  interface Cradle {
    regimensRepository: RegimensRepository;
    regimensService: RegimensService;
  }
}

export default fp(
  async (fastify) => {
    fastify.diContainer.register({
      regimensRepository: asClass(RegimensRepository, { lifetime: Lifetime.SINGLETON }),
      regimensService: asClass(RegimensService, { lifetime: Lifetime.SINGLETON }),
    });

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

    // GET /api/v1/households/:householdId/regimens — list user's regimens
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/regimens',
      schema: {
        params: householdParams,
        querystring: RegimenQuerySchema,
        response: { 200: RegimenListResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        const result = await service.list(
          request.params.householdId,
          request.user.keycloakId,
          request.query,
        );
        return reply.send({
          data: result.data.map(toRegimenResponse),
          pagination: result.pagination,
        });
      },
    });

    // GET /api/v1/households/:householdId/regimens/burn-rate — burn rate + spending projection
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/regimens/burn-rate',
      schema: {
        params: householdParams,
        response: { 200: BurnRateResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        const data = await service.calculateBurnRates(
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.send({ data });
      },
    });

    // GET /api/v1/households/:householdId/regimens/:id — get single regimen
    app.route({
      method: 'GET',
      url: '/api/v1/households/:householdId/regimens/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        response: { 200: RegimenResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        const regimen = await service.getById(
          request.params.id,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.send(toRegimenResponse(regimen));
      },
    });

    // POST /api/v1/households/:householdId/regimens — create regimen
    app.route({
      method: 'POST',
      url: '/api/v1/households/:householdId/regimens',
      schema: {
        params: householdParams,
        body: CreateRegimenSchema,
        response: { 201: RegimenResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        const regimen = await service.create(
          request.body,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.status(201).send(toRegimenResponse(regimen));
      },
    });

    // PATCH /api/v1/households/:householdId/regimens/:id — update regimen
    app.route({
      method: 'PATCH',
      url: '/api/v1/households/:householdId/regimens/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        body: UpdateRegimenSchema,
        response: { 200: RegimenResponseSchema },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        const regimen = await service.update(
          request.params.id,
          request.params.householdId,
          request.user.keycloakId,
          request.body,
        );
        return reply.send(toRegimenResponse(regimen));
      },
    });

    // DELETE /api/v1/households/:householdId/regimens/:id — delete regimen
    app.route({
      method: 'DELETE',
      url: '/api/v1/households/:householdId/regimens/:id',
      schema: {
        params: householdParams.extend({ id: z.string() }),
        response: { 204: z.undefined() },
      },
      handler: async (request, reply) => {
        const service = fastify.diContainer.resolve('regimensService');
        await service.delete(
          request.params.id,
          request.params.householdId,
          request.user.keycloakId,
        );
        return reply.status(204).send();
      },
    });
  },
  {
    name: 'regimens-routes',
    dependencies: ['auth-plugin'],
  },
);
