import { eq } from "drizzle-orm";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import * as schema from "./schema/index.js";

type Db = NodePgDatabase<typeof schema>;

export interface ActivationState {
  firstScanCompletedAt: Date | null;
  fifthItemConfirmedAt: Date | null;
  firstRecipeRecommendationViewedAt: Date | null;
  firstRecipeSavedOrStartedAt: Date | null;
  activatedAt: Date | null;
  firstCookingSessionCompletedAt: Date | null;
  inventoryUpdatedAfterCookingAt: Date | null;
  valueConfirmedAt: Date | null;
}

function milestoneColumn(milestone: keyof ActivationState) {
  return schema.households[milestone] as (typeof schema.households)["firstScanCompletedAt"];
}

const activationMilestones: Array<keyof ActivationState> = [
  "firstScanCompletedAt",
  "fifthItemConfirmedAt",
  "firstRecipeRecommendationViewedAt",
  "firstRecipeSavedOrStartedAt",
  "activatedAt",
  "firstCookingSessionCompletedAt",
  "inventoryUpdatedAfterCookingAt",
  "valueConfirmedAt",
];

function isActivationMilestone(m: string): m is keyof ActivationState {
  return activationMilestones.includes(m as keyof ActivationState);
}

/**
 * Markera en milstolpe och utvärdera aktiveringsstatus.
 * Endast den första bekräftelsen sparas; anrop är idempotenta.
 */
export async function markMilestone(
  db: Db,
  householdId: string,
  milestone: keyof ActivationState,
): Promise<{ wasNew: boolean; activatedNow: boolean; valueConfirmedNow: boolean }> {
  if (!isActivationMilestone(milestone)) {
    throw new Error(`Unknown activation milestone: ${milestone}`);
  }

  const [before] = await db
    .select({
      milestoneAt: milestoneColumn(milestone),
      firstScanCompletedAt: schema.households.firstScanCompletedAt,
      fifthItemConfirmedAt: schema.households.fifthItemConfirmedAt,
      firstRecipeRecommendationViewedAt: schema.households.firstRecipeRecommendationViewedAt,
      firstRecipeSavedOrStartedAt: schema.households.firstRecipeSavedOrStartedAt,
      activatedAt: schema.households.activatedAt,
      firstCookingSessionCompletedAt: schema.households.firstCookingSessionCompletedAt,
      inventoryUpdatedAfterCookingAt: schema.households.inventoryUpdatedAfterCookingAt,
      valueConfirmedAt: schema.households.valueConfirmedAt,
    })
    .from(schema.households)
    .where(eq(schema.households.id, householdId));

  if (!before) {
    throw new Error(`Household not found: ${householdId}`);
  }

  const wasNew = before.milestoneAt == null;
  const wasActivated = before.activatedAt != null;
  const wasValueConfirmed = before.valueConfirmedAt != null;

  if (!wasNew) {
    return { wasNew: false, activatedNow: false, valueConfirmedNow: false };
  }

  const isActivatedNow =
    before.firstScanCompletedAt != null &&
    before.fifthItemConfirmedAt != null &&
    before.firstRecipeRecommendationViewedAt != null &&
    (before.firstRecipeSavedOrStartedAt != null || milestone === "firstRecipeSavedOrStartedAt");

  const activatedNow = !wasActivated && isActivatedNow;

  const isValueConfirmedNow =
    isActivatedNow &&
    (before.firstCookingSessionCompletedAt != null || milestone === "firstCookingSessionCompletedAt") &&
    (before.inventoryUpdatedAfterCookingAt != null || milestone === "inventoryUpdatedAfterCookingAt");

  const valueConfirmedNow = !wasValueConfirmed && isValueConfirmedNow;

  const updates: Partial<typeof schema.households.$inferInsert> = {
    [milestone]: new Date(),
    updatedAt: new Date(),
  };

  if (activatedNow) {
    updates.activatedAt = new Date();
  }
  if (valueConfirmedNow) {
    updates.valueConfirmedAt = new Date();
  }

  await db.update(schema.households).set(updates).where(eq(schema.households.id, householdId));

  return { wasNew, activatedNow, valueConfirmedNow };
}

export async function getActivationState(db: Db, householdId: string): Promise<ActivationState> {
  const [row] = await db
    .select({
      firstScanCompletedAt: schema.households.firstScanCompletedAt,
      fifthItemConfirmedAt: schema.households.fifthItemConfirmedAt,
      firstRecipeRecommendationViewedAt: schema.households.firstRecipeRecommendationViewedAt,
      firstRecipeSavedOrStartedAt: schema.households.firstRecipeSavedOrStartedAt,
      activatedAt: schema.households.activatedAt,
      firstCookingSessionCompletedAt: schema.households.firstCookingSessionCompletedAt,
      inventoryUpdatedAfterCookingAt: schema.households.inventoryUpdatedAfterCookingAt,
      valueConfirmedAt: schema.households.valueConfirmedAt,
    })
    .from(schema.households)
    .where(eq(schema.households.id, householdId));

  return row ?? {
    firstScanCompletedAt: null,
    fifthItemConfirmedAt: null,
    firstRecipeRecommendationViewedAt: null,
    firstRecipeSavedOrStartedAt: null,
    activatedAt: null,
    firstCookingSessionCompletedAt: null,
    inventoryUpdatedAfterCookingAt: null,
    valueConfirmedAt: null,
  };
}
