import type { FastifyInstance } from "fastify";
import { eq } from "drizzle-orm";
import { z } from "zod";
import { schema } from "@app/database";
import { quickStartInputSchema, onboardingInputSchema } from "@app/validation";
import { errors, parse } from "../lib/errors.js";
import {
  audit,
  createHouseholdWithDefaults,
  getActiveHouseholdId,
} from "../lib/helpers.js";

import { t } from "../lib/i18n.js";
import { KNOWN_FLAGS } from "@app/feature-flags";

/**
 * Progressive onboarding (FAS 1b): 3-layer flow.
 * Step A = immediate value (goal + precision mode).
 * Step B = after first value (diet, allergens, household).
 * Step C = contextual (health profile, deep preferences).
 *
 * Preserves existing /v1/me/onboarding for backward compatibility.
 */
export async function onboardingRoutes(app: FastifyInstance) {
  const auth = { preHandler: [app.authenticate] };

  /** GET /v1/onboarding/status – where is the user in the progressive flow? */
  app.get("/v1/onboarding/status", auth, async (req) => {
    const [user] = await app.db
      .select({
        onboardingCompleted: schema.users.onboardingCompleted,
        onboardingStep: schema.users.onboardingStep,
      })
      .from(schema.users)
      .where(eq(schema.users.id, req.userId))
      .limit(1);
    if (!user) throw errors.notFound();

    const householdId = await getActiveHouseholdId(app.db, req.userId);
    const [health] = await app.db
      .select({ userId: schema.userHealthProfiles.userId })
      .from(schema.userHealthProfiles)
      .where(eq(schema.userHealthProfiles.userId, req.userId))
      .limit(1);
    const [prefs] = await app.db
      .select({ userId: schema.userPreferences.userId })
      .from(schema.userPreferences)
      .where(eq(schema.userPreferences.userId, req.userId))
      .limit(1);

    // Feature-flag: progressive onboarding rollout
    const progressiveEnabled = await app.flags.isEnabled(
      KNOWN_FLAGS.PROGRESSIVE_ONBOARDING,
      req.userId,
    );

    return {
      step: user.onboardingStep,
      onboardingCompleted: user.onboardingCompleted,
      hasHousehold: householdId != null,
      hasHealthProfile: health != null,
      hasPreferences: prefs != null,
      progressiveEnabled,
    };
  });

  /** POST /v1/onboarding/quick-start – complete Step A (minimal, immediate value). */
  app.post("/v1/onboarding/quick-start", auth, async (req) => {
    const input = parse(quickStartInputSchema, req.body);

    // Normalize goals: multi-select UI sends `goals`; legacy clients send `primaryGoal`.
    const goals = input.goals?.length
      ? input.goals
      : input.primaryGoal
        ? [input.primaryGoal]
        : [];
    const primaryGoal = goals[0];

    // Upsert minimal preferences
    await app.db
      .insert(schema.userPreferences)
      .values({
        userId: req.userId,
        goals,
        ...(primaryGoal ? { primaryGoal } : {}),
      })
      .onConflictDoUpdate({
        target: schema.userPreferences.userId,
        set: {
          goals,
          ...(primaryGoal ? { primaryGoal } : {}),
          updatedAt: new Date(),
        },
      });

    // Auto-create a household so the user can scan, shop, plan and budget
    // immediately instead of hitting the "no household" wall in 21 endpoints.
    let householdId = await getActiveHouseholdId(app.db, req.userId);
    if (!householdId) {
      const [user] = await app.db
        .select({ locale: schema.users.locale })
        .from(schema.users)
        .where(eq(schema.users.id, req.userId))
        .limit(1);
      const householdName = t("onboarding.householdDefaultName", user?.locale ?? "sv-SE");
      const household = await createHouseholdWithDefaults(app.db, {
        userId: req.userId,
        name: householdName,
        size: input.persons,
      });
      householdId = household.id;
    }

    // Advance to step B
    const [user] = await app.db
      .update(schema.users)
      .set({
        precisionMode: input.precisionMode,
        onboardingStep: "b",
        updatedAt: new Date(),
      })
      .where(eq(schema.users.id, req.userId))
      .returning();

    await audit(app.db, {
      actorUserId: req.userId,
      action: "onboarding.quick_start",
      metadata: { goals, primaryGoal, precisionMode: input.precisionMode, householdId },
      ip: req.ip,
      correlationId: req.correlationId,
    });

    return {
      ok: true,
      step: user!.onboardingStep,
      onboardingCompleted: user!.onboardingCompleted,
      householdId,
    };
  });

  /** POST /v1/onboarding/complete-b – complete Step B (diet, allergens, household). */
  app.post("/v1/onboarding/complete-b", auth, async (req) => {
    const input = parse(onboardingInputSchema, req.body);

    if (input.preferences) {
      await app.db
        .insert(schema.userPreferences)
        .values({ userId: req.userId, ...input.preferences })
        .onConflictDoUpdate({
          target: schema.userPreferences.userId,
          set: { ...input.preferences, updatedAt: new Date() },
        });
    }

    let householdId: string | null = await getActiveHouseholdId(app.db, req.userId);
    if (input.householdChoice.kind === "create") {
      if (householdId) {
        // Auto-created household already exists; update name if user provided a custom one.
        await app.db
          .update(schema.households)
          .set({ name: input.householdChoice.name, updatedAt: new Date() })
          .where(eq(schema.households.id, householdId));
      } else {
        const household = await createHouseholdWithDefaults(app.db, {
          userId: req.userId,
          name: input.householdChoice.name,
        });
        householdId = household.id;
      }
    } else if (input.householdChoice.kind === "join") {
      const [household] = await app.db
        .select()
        .from(schema.households)
        .where(eq(schema.households.inviteCode, input.householdChoice.inviteCode.toUpperCase()))
        .limit(1);
      if (!household) throw errors.notFound("Ingen hushållsinbjudan matchar koden.");
      await app.db
        .insert(schema.householdMembers)
        .values({ householdId: household.id, userId: req.userId, role: "adult" })
        .onConflictDoNothing();
      householdId = household.id;
    }

    // Advance to step C (or mark completed if no health profile needed)
    const [user] = await app.db
      .update(schema.users)
      .set({
        precisionMode: input.precisionMode,
        onboardingStep: "c",
        updatedAt: new Date(),
      })
      .where(eq(schema.users.id, req.userId))
      .returning();

    await audit(app.db, {
      actorUserId: req.userId,
      action: "onboarding.complete_b",
      metadata: { householdId, hasPreferences: !!input.preferences },
      ip: req.ip,
      correlationId: req.correlationId,
    });

    return { ok: true, step: user!.onboardingStep, householdId };
  });

  /** POST /v1/onboarding/complete-c – complete Step C (health profile, final). */
  app.post("/v1/onboarding/complete-c", auth, async (req) => {
    const input = parse(onboardingInputSchema, req.body);

    if (input.healthProfile) {
      await app.db
        .insert(schema.userHealthProfiles)
        .values({ userId: req.userId, ...input.healthProfile })
        .onConflictDoUpdate({
          target: schema.userHealthProfiles.userId,
          set: { ...input.healthProfile, updatedAt: new Date() },
        });
    }

    if (input.preferences) {
      await app.db
        .insert(schema.userPreferences)
        .values({ userId: req.userId, ...input.preferences })
        .onConflictDoUpdate({
          target: schema.userPreferences.userId,
          set: { ...input.preferences, updatedAt: new Date() },
        });
    }

    const [user] = await app.db
      .update(schema.users)
      .set({
        precisionMode: input.precisionMode,
        onboardingStep: "c",
        onboardingCompleted: true,
        updatedAt: new Date(),
      })
      .where(eq(schema.users.id, req.userId))
      .returning();

    await audit(app.db, {
      actorUserId: req.userId,
      action: "onboarding.complete_c",
      metadata: { hasHealthProfile: !!input.healthProfile },
      ip: req.ip,
      correlationId: req.correlationId,
    });

    return { ok: true, onboardingCompleted: user!.onboardingCompleted };
  });

  /** POST /v1/onboarding/skip – skip remaining steps (GDPR-friendly, user's choice). */
  app.post("/v1/onboarding/skip", auth, async (req) => {
    const body = parse(
      z.object({ step: z.enum(["b", "c"]).optional() }),
      req.body,
    );

    const [user] = await app.db
      .update(schema.users)
      .set({
        onboardingStep: "c",
        onboardingCompleted: true,
        updatedAt: new Date(),
      })
      .where(eq(schema.users.id, req.userId))
      .returning();

    await audit(app.db, {
      actorUserId: req.userId,
      action: "onboarding.skipped",
      metadata: { skippedStep: body.step ?? "all" },
      ip: req.ip,
      correlationId: req.correlationId,
    });

    return { ok: true, onboardingCompleted: user!.onboardingCompleted };
  });
}
