import { FastifyInstance } from "fastify";
import { z } from "zod";
import { db } from "../db/client.js";
import { medications, refillHistory } from "../db/schema.js";
import { eq, and, desc } from "drizzle-orm";
import { requireAuth, getAnonymousUserId } from "../plugins/auth.js";
import { env } from "../plugins/env.js";
import type { AuthUser } from "../types/fastify.js";

const refillSchema = z.object({
  packsAdded: z.number().int().min(0).default(0),
  loosePillsAdded: z.number().int().min(0).default(0),
}).refine(data => data.packsAdded > 0 || data.loosePillsAdded > 0, {
  message: "Must add at least one pack or some loose pills",
});

export async function refillRoutes(app: FastifyInstance) {
  // All refill routes require auth
  app.addHook("preHandler", requireAuth);

  // Helper to get user ID from request
  async function getUserId(request: any, reply: any): Promise<number> {
    if (!env.AUTH_ENABLED) {
      return getAnonymousUserId();
    }
    const authUser = request.user as unknown as AuthUser | null;
    if (!authUser) {
      reply.status(401).send({ error: "User not authenticated", code: "AUTH_REQUIRED" });
      throw new Error("AUTH_REQUIRED");
    }
    return authUser.id;
  }

  // POST /medications/:id/refill - Add stock to medication
  app.post<{ Params: { id: string } }>("/medications/:id/refill", async (req, reply) => {
    const parsed = refillSchema.safeParse(req.body);
    if (!parsed.success) return reply.status(400).send(parsed.error.format());

    const medId = Number(req.params.id);
    if (Number.isNaN(medId)) return reply.badRequest("Invalid medication id");

    const userId = await getUserId(req, reply);

    // Verify ownership
    const [med] = await db.select().from(medications).where(
      and(eq(medications.id, medId), eq(medications.userId, userId))
    );
    if (!med) return reply.notFound("Medication not found");

    const { packsAdded, loosePillsAdded } = parsed.data;

    // Update medication stock
    const newPackCount = med.packCount + packsAdded;
    const newLooseTablets = med.looseTablets + loosePillsAdded;

    await db.update(medications)
      .set({
        packCount: newPackCount,
        looseTablets: newLooseTablets,
        updatedAt: new Date(),
      })
      .where(and(eq(medications.id, medId), eq(medications.userId, userId)));

    // Create refill history entry
    const [refill] = await db.insert(refillHistory)
      .values({
        medicationId: medId,
        userId,
        packsAdded,
        loosePillsAdded,
      })
      .returning();

    // Calculate pills added for response
    const pillsPerPack = med.blistersPerPack * med.pillsPerBlister;
    const totalPillsAdded = (packsAdded * pillsPerPack) + loosePillsAdded;

    return {
      success: true,
      refill: {
        id: refill.id,
        packsAdded,
        loosePillsAdded,
        totalPillsAdded,
        refillDate: refill.refillDate,
      },
      newStock: {
        packCount: newPackCount,
        looseTablets: newLooseTablets,
        totalPills: newPackCount * pillsPerPack + newLooseTablets,
      },
    };
  });

  // GET /medications/:id/refills - Get refill history for a medication
  app.get<{ Params: { id: string } }>("/medications/:id/refills", async (req, reply) => {
    const medId = Number(req.params.id);
    if (Number.isNaN(medId)) return reply.badRequest("Invalid medication id");

    const userId = await getUserId(req, reply);

    // Verify ownership
    const [med] = await db.select().from(medications).where(
      and(eq(medications.id, medId), eq(medications.userId, userId))
    );
    if (!med) return reply.notFound("Medication not found");

    // Get refill history, newest first
    const refills = await db.select()
      .from(refillHistory)
      .where(eq(refillHistory.medicationId, medId))
      .orderBy(desc(refillHistory.refillDate));

    const pillsPerPack = med.blistersPerPack * med.pillsPerBlister;

    return refills.map(r => ({
      id: r.id,
      packsAdded: r.packsAdded,
      loosePillsAdded: r.loosePillsAdded,
      totalPillsAdded: (r.packsAdded * pillsPerPack) + r.loosePillsAdded,
      refillDate: r.refillDate,
    }));
  });
}
