import { query } from "../_generated/server";
import type { Id } from "../_generated/dataModel";
import { v } from "convex/values";

/**
 * Get the currently authenticated user via Clerk identity.
 * Primary lookup: by_clerkId index (identity.subject = Clerk user ID).
 * Falls back to by_email for users created before clerkId was populated.
 * Phase 1: Auth & Organizations
 */
export const getCurrentUser = query({
  args: {},
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) return null;

    // Primary: clerkId lookup (indexed, most reliable)
    const userByClerkId = await ctx.db
      .query("users")
      .withIndex("by_clerkId", (q) => q.eq("clerkId", identity.subject))
      .unique();
    if (userByClerkId) return userByClerkId;

    // Fallback: email lookup for users not yet backfilled with clerkId
    if (identity.email) {
      return await ctx.db
        .query("users")
        .withIndex("by_email", (q) => q.eq("email", identity.email!))
        .unique();
    }

    return null;
  },
});

/**
 * Get user by ID
 * Phase 1: Auth & Organizations
 */
export const getUser = query({
  args: { id: v.id("users") },
  handler: async (ctx, args) => {
    return await ctx.db.get(args.id);
  },
});

/**
 * Get user by Clerk user ID (identity.subject)
 * Phase 1: Auth & Organizations
 */
export const getUserByClerkId = query({
  args: { clerkId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("users")
      .withIndex("by_clerkId", (q) => q.eq("clerkId", args.clerkId))
      .unique();
  },
});

/**
 * Resolve a user by any app-level ID (appUserId, prismaId, or Convex _id).
 * Used by convex-auth-state.ts for session resolution.
 */
async function findUserByAnyAppId(ctx: any, id: string) {
  // 1. appUserId index
  let user = await ctx.db
    .query("users")
    .withIndex("by_appUserId", (q: any) => q.eq("appUserId", id))
    .first();
  if (user) return user;

  // 2. prismaId filter
  user = await ctx.db
    .query("users")
    .filter((q: any) => q.eq(q.field("prismaId"), id))
    .first();
  if (user) return user;

  // 3. Convex document _id
  try {
    return await ctx.db.get(id as Id<"users">);
  } catch {
    return null;
  }
}

/**
 * Get only the companyName by app-level user ID.
 * Returns a single string — no user record exposed.
 * Used by widget-settings API for default business name.
 */
export const getCompanyNameByAppUserId = query({
  args: { appUserId: v.string() },
  handler: async (ctx, args) => {
    const user = await findUserByAnyAppId(ctx, args.appUserId);
    return user?.companyName ?? null;
  },
});

/**
 * Get user by email address
 * Phase 1: Auth & Organizations
 */
export const getUserByEmail = query({
  args: { email: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("users")
      .withIndex("by_email", (q) => q.eq("email", args.email))
      .unique();
  },
});

/**
 * Get user by Google ID (OAuth identity lookup)
 * Phase 1: Auth & Organizations
 */
export const getUserByGoogleId = query({
  args: { googleId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("users")
      .withIndex("by_googleId", (q) => q.eq("googleId", args.googleId))
      .unique();
  },
});

/**
 * Get active session for a user
 * Phase 1: Auth & Organizations
 */
export const getSession = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("user_sessions")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .order("desc")
      .first();
  },
});

/**
 * List all sessions for a user (ordered newest first)
 * Phase 1: Auth & Organizations
 */
export const listUserSessions = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) return [];
    return await ctx.db
      .query("user_sessions")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .order("desc")
      .collect();
  },
});

/**
 * Get login history for a user (paginated)
 * Phase 1: Auth & Organizations
 */
export const getLoginHistory = query({
  args: {
    userId: v.string(),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const limit = args.limit ?? 20;
    return await ctx.db
      .query("login_history")
      .withIndex("by_userId_createdAt", (q) => q.eq("userId", args.userId))
      .order("desc")
      .take(limit);
  },
});

/**
 * Get user profile with organization memberships
 * Phase 1: Auth & Organizations
 */
export const getUserProfile = query({
  args: { userId: v.id("users") },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) return null;
    const user = await ctx.db.get(args.userId);
    if (!user) return null;
    const memberships = await ctx.db
      .query("organization_members")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .collect();
    return { user, memberships };
  },
});

// ── OTP Queries ─────────────────────────────────────────────────────

/**
 * Get the latest OTP for an email address
 * No auth check — called during login/signup flows.
 */
export const getOtpByEmail = query({
  args: { email: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("otps")
      .withIndex("by_email", (q) => q.eq("email", args.email))
      .order("desc")
      .first();
  },
});

/**
 * Get a reset token for an email address
 * No auth check — called during password reset flows.
 */
export const getResetToken = query({
  args: { email: v.string() },
  handler: async (ctx, args) => {
    const record = await ctx.db
      .query("otps")
      .withIndex("by_email", (q) => q.eq("email", args.email))
      .order("desc")
      .first();

    if (!record || record.purpose !== "PASSWORD_RESET") return null;
    if (record.expires_at < Date.now()) return null;

    return {
      token: record.otp_code,
      email: record.email,
      expiresAt: record.expires_at,
    };
  },
});

// ── User Preferences Queries ─────────────────────────────────────────

/**
 * Get user preferences by userId
 */
export const getUserPreferences = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("user_preferences")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .unique();
  },
});

// ── User Links Queries ───────────────────────────────────────────────

/**
 * Get active user links, sorted by sortOrder
 */
export const getUserLinks = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    const links = await ctx.db
      .query("user_links")
      .withIndex("by_userId_isActive", (q) =>
        q.eq("userId", args.userId).eq("isActive", true),
      )
      .collect();
    return links.sort((a, b) => a.sortOrder - b.sortOrder);
  },
});

// ── Audit Log Queries ────────────────────────────────────────────────

/**
 * Get audit log entries for a user with optional type filter and pagination
 */
export const getAuditLogs = query({
  args: {
    userId: v.string(),
    type: v.optional(v.string()),
    limit: v.optional(v.number()),
    offset: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const limit = args.limit ?? 20;
    const offset = args.offset ?? 0;

    let q;
    if (args.type) {
      q = ctx.db
        .query("audit_logs")
        .withIndex("by_userId_type_createdAt", (qb) =>
          qb.eq("userId", args.userId).eq("type", args.type!),
        )
        .order("desc");
    } else {
      q = ctx.db
        .query("audit_logs")
        .withIndex("by_userId_createdAt", (qb) => qb.eq("userId", args.userId))
        .order("desc");
    }

    // Collect all matching, then apply offset/limit manually
    const all = await q.collect();
    const total = all.length;
    const events = all.slice(offset, offset + limit);
    return { events, total };
  },
});

// ── Onboarding Progress Queries ──────────────────────────────────────

/**
 * Get onboarding progress for a user
 */
export const getOnboardingProgress = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("onboarding_progress")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .unique();
  },
});

// ── Organization Member Queries (for profile route) ──────────────────

/**
 * Get a user's organization membership (role + org ID)
 */
export const getUserOrganizationMembership = query({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("organization_members")
      .withIndex("by_userId", (q) => q.eq("userId", args.userId))
      .first();
  },
});
