import {
  boolean,
  doublePrecision,
  index,
  integer,
  pgTable,
  primaryKey,
  text,
  timestamp,
  uniqueIndex,
  uuid,
} from "drizzle-orm/pg-core";
import {
  activityLevelEnum,
  allergenEnum,
  consentKindEnum,
  consentStatusEnum,
  createdAt,
  dietPatternEnum,
  goalTypeEnum,
  precisionModeEnum,
  religiousRuleEnum,
  sexEnum,
  updatedAt,
  userRoleEnum,
  cuisineEnum,
} from "./_shared.js";

/** Kontodata. Hälsodata ligger i user_health_profiles (separationskrav, spec §56). */
export const users = pgTable(
  "users",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    email: text("email").notNull(),
    /** null = e-posten ej verifierad ännu (icke-blockerande – appen fungerar ändå). */
    emailVerifiedAt: timestamp("email_verified_at", { withTimezone: true }),
    displayName: text("display_name").notNull(),
    role: userRoleEnum("role").notNull().default("user"),
    locale: text("locale").notNull().default("sv-SE"),
    precisionMode: precisionModeEnum("precision_mode").notNull().default("simple"),
    onboardingCompleted: boolean("onboarding_completed").notNull().default(false),
    deletedAt: timestamp("deleted_at", { withTimezone: true }),
    createdAt: createdAt(),
    updatedAt: updatedAt(),
  },
  (t) => [uniqueIndex("users_email_unique").on(t.email)],
);

/** Autentiseringsuppgifter separerade från kontot (byts utan att röra users). */
export const userCredentials = pgTable("user_credentials", {
  userId: uuid("user_id")
    .primaryKey()
    .references(() => users.id, { onDelete: "cascade" }),
  /** scrypt-hash i formatet scrypt$N$r$p$salt$hash (ingen extern native-dependency). */
  passwordHash: text("password_hash").notNull(),
  passwordUpdatedAt: timestamp("password_updated_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

/** Admin-2FA (TOTP, RFC 6238). Endast admin-konton; secret per användare. */
export const adminTotp = pgTable("admin_totp", {
  userId: uuid("user_id")
    .primaryKey()
    .references(() => users.id, { onDelete: "cascade" }),
  secretBase32: text("secret_base32").notNull(),
  /** null = setup påbörjad men inte bekräftad med kod ännu. */
  enabledAt: timestamp("enabled_at", { withTimezone: true }),
  /** Senast accepterade TOTP-steg – förhindrar återanvändning inom fönstret. */
  lastUsedStep: integer("last_used_step"),
  createdAt: createdAt(),
});

/** E-postverifiering av konton. Samma säkerhetsmodell som lösenordsåterställning. */
export const emailVerificationTokens = pgTable(
  "email_verification_tokens",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    tokenHash: text("token_hash").notNull(),
    expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
    usedAt: timestamp("used_at", { withTimezone: true }),
    createdAt: createdAt(),
  },
  (t) => [
    index("email_verification_tokens_user_idx").on(t.userId),
    uniqueIndex("email_verification_tokens_hash_unique").on(t.tokenHash),
  ],
);

/**
 * Lösenordsåterställning via e-post. Token lagras ENDAST hashad (sha256),
 * 30 min TTL, engångsbruk; alla tidigare oanvända tokens ogiltigförklaras
 * när en ny begärs. Svaret på forgot-password avslöjar aldrig om kontot finns.
 */
export const passwordResetTokens = pgTable(
  "password_reset_tokens",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    tokenHash: text("token_hash").notNull(),
    expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
    usedAt: timestamp("used_at", { withTimezone: true }),
    createdAt: createdAt(),
  },
  (t) => [
    index("password_reset_tokens_user_idx").on(t.userId),
    uniqueIndex("password_reset_tokens_hash_unique").on(t.tokenHash),
  ],
);

/** Roterande refresh-tokens, lagrade hashade (spec §56: säker tokenhantering). */
export const refreshTokens = pgTable(
  "refresh_tokens",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    tokenHash: text("token_hash").notNull(),
    familyId: uuid("family_id").notNull(),
    expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
    revokedAt: timestamp("revoked_at", { withTimezone: true }),
    replacedByTokenId: uuid("replaced_by_token_id"),
    userAgent: text("user_agent"),
    ip: text("ip"),
    createdAt: createdAt(),
  },
  (t) => [
    index("refresh_tokens_user_idx").on(t.userId),
    uniqueIndex("refresh_tokens_hash_unique").on(t.tokenHash),
  ],
);

/**
 * Hälsoprofil – logiskt och behörighetsmässigt separerad från hushållsdata
 * (spec §7, §56). Delas aldrig med andra hushållsmedlemmar.
 */
export const userHealthProfiles = pgTable("user_health_profiles", {
  userId: uuid("user_id")
    .primaryKey()
    .references(() => users.id, { onDelete: "cascade" }),
  birthYear: integer("birth_year"),
  sex: sexEnum("sex"),
  heightCm: doublePrecision("height_cm"),
  weightKg: doublePrecision("weight_kg"),
  targetWeightKg: doublePrecision("target_weight_kg"),
  activityLevel: activityLevelEnum("activity_level").notNull().default("moderate"),
  trainingSessionsPerWeek: integer("training_sessions_per_week"),
  trainingTypes: text("training_types").array().notNull().default([]),
  updatedAt: updatedAt(),
});

export const userPreferences = pgTable("user_preferences", {
  userId: uuid("user_id")
    .primaryKey()
    .references(() => users.id, { onDelete: "cascade" }),
  primaryGoal: goalTypeEnum("primary_goal"),
  goals: goalTypeEnum("goals").array().notNull().default([]),
  dietPattern: dietPatternEnum("diet_pattern").notNull().default("omnivore"),
  religiousRule: religiousRuleEnum("religious_rule").notNull().default("none"),
  /** Deterministisk allergifiltrering utgår härifrån (spec §61.2). */
  allergens: allergenEnum("allergens").array().notNull().default([]),
  intolerances: text("intolerances").array().notNull().default([]),
  avoidIngredientIds: text("avoid_ingredient_ids").array().notNull().default([]),
  favoriteCuisines: cuisineEnum("favorite_cuisines").array().notNull().default([]),
  dislikedDishes: text("disliked_dishes").array().notNull().default([]),
  spiceLevelMax: integer("spice_level_max").notNull().default(3),
  weeklyBudgetMinor: integer("weekly_budget_minor"),
  maxCookingMinutesWeekday: integer("max_cooking_minutes_weekday"),
  equipment: text("equipment").array().notNull().default([]),
  defaultPortions: integer("default_portions").notNull().default(2),
  updatedAt: updatedAt(),
});

/** Separata samtycken (spec §33): personlig funktion ≠ anonymiserad förbättring ≠ bildträning. */
export const userConsents = pgTable(
  "user_consents",
  {
    userId: uuid("user_id")
      .notNull()
      .references(() => users.id, { onDelete: "cascade" }),
    kind: consentKindEnum("kind").notNull(),
    status: consentStatusEnum("status").notNull(),
    grantedAt: timestamp("granted_at", { withTimezone: true }),
    revokedAt: timestamp("revoked_at", { withTimezone: true }),
    updatedAt: updatedAt(),
  },
  (t) => [primaryKey({ columns: [t.userId, t.kind] })],
);
