import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
import { supabaseAdmin } from "@/integrations/supabase/client.server";

async function assertAdminAccess(supabase: any, userId: string) {
  const { data: isAdminRow, error: roleErr } = await supabase
    .from("user_roles")
    .select("role")
    .eq("user_id", userId)
    .eq("role", "admin")
    .maybeSingle();

  if (roleErr) throw new Error(roleErr.message);
  if (!isAdminRow) throw new Error("Only admins can manage users");
}

export const listAdminUsersFn = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    await assertAdminAccess(context.supabase, context.userId);

    const [profilesRes, rolesRes] = await Promise.all([
      supabaseAdmin.from("profiles").select("id, full_name, mobile, username, status, branch_id, custom_role_id, created_at, last_login"),
      supabaseAdmin.from("user_roles").select("id, user_id, role"),
    ]);

    if (profilesRes.error) throw new Error(profilesRes.error.message);
    if (rolesRes.error) throw new Error(rolesRes.error.message);

    const authUsers: Array<{
      id: string;
      email?: string | null;
      created_at?: string | null;
      last_sign_in_at?: string | null;
      email_confirmed_at?: string | null;
      user_metadata?: { full_name?: string | null };
    }> = [];

    let page = 1;
    const perPage = 1000;
    while (true) {
      const { data, error } = await supabaseAdmin.auth.admin.listUsers({ page, perPage });
      if (error) throw new Error(error.message);

      const batch = (data?.users ?? []) as typeof authUsers;
      authUsers.push(...batch);

      if (batch.length < perPage) break;
      page += 1;
    }

    const profileMap = new Map((profilesRes.data ?? []).map((profile) => [profile.id, profile]));
    const roleMap = new Map<string, Array<{ id: string; role: "admin" | "staff" | "user" }>>();

    for (const roleRow of rolesRes.data ?? []) {
      const current = roleMap.get(roleRow.user_id) ?? [];
      current.push({ id: roleRow.id, role: roleRow.role });
      roleMap.set(roleRow.user_id, current);
    }

    const userIds = new Set<string>([
      ...authUsers.map((user) => user.id),
      ...(profilesRes.data ?? []).map((profile) => profile.id),
    ]);

    return Array.from(userIds)
      .map((userId) => {
        const authUser = authUsers.find((user) => user.id === userId);
        const profile = profileMap.get(userId);

        return {
          id: userId,
          email: authUser?.email ?? "",
          full_name: profile?.full_name ?? authUser?.user_metadata?.full_name ?? "",
          mobile: profile?.mobile ?? "",
          username: profile?.username ?? "",
          status: profile?.status ?? "active",
          branch_id: profile?.branch_id ?? null,
          custom_role_id: profile?.custom_role_id ?? null,
          created_at: profile?.created_at ?? authUser?.created_at ?? null,
          last_login: profile?.last_login ?? authUser?.last_sign_in_at ?? null,
          email_confirmed_at: authUser?.email_confirmed_at ?? null,
          roles: roleMap.get(userId) ?? [],
        };
      })
      .sort((a, b) => {
        const aTime = a.created_at ? new Date(a.created_at).getTime() : 0;
        const bTime = b.created_at ? new Date(b.created_at).getTime() : 0;
        return bTime - aTime;
      });
  });

export const createUserFn = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: unknown) =>
    z
      .object({
        email: z.string().email().max(255),
        password: z.string().min(6).max(128),
        full_name: z.string().min(1).max(100),
        mobile: z.string().max(30).optional().default(""),
        username: z.string().max(50).optional().default(""),
        branch_id: z.string().uuid().optional().nullable(),
        system_role: z.enum(["admin", "staff", "user"]).default("staff"),
        custom_role_id: z.string().uuid().optional().nullable(),
        staff_record: z
          .object({
            name: z.string().min(1).max(100),
            mobile: z.string().max(30).optional().default(""),
            email: z.string().email().max(255).optional(),
            address: z.string().max(500).optional().default(""),
            role: z.string().max(50).optional().default("sales"),
            designation: z.string().max(100).optional().default(""),
            nid: z.string().max(50).optional().default(""),
            username: z.string().max(50).optional().nullable(),
            joining_date: z.string().optional().nullable(),
            salary: z.number().min(0).optional().default(0),
            commission_rate: z.number().min(0).optional().default(0),
            status: z.string().max(20).optional().default("active"),
            note: z.string().max(2000).optional().default(""),
            branch_id: z.string().uuid().optional().nullable(),
            department_id: z.string().uuid().optional().nullable(),
            photo_url: z.string().max(2000).optional().default(""),
          })
          .optional(),
      })
      .parse(input)
  )
  .handler(async ({ data, context }) => {
    await assertAdminAccess(context.supabase, context.userId);

    // Pre-check unique constraints on profiles.mobile / username so we don't end up
    // with an auth.users row that can't get a matching profile.
    if (data.mobile) {
      const { data: dupMobile } = await supabaseAdmin
        .from("profiles")
        .select("id")
        .eq("mobile", data.mobile)
        .maybeSingle();
      if (dupMobile) throw new Error(`এই mobile ইতিমধ্যে অন্য user-এর সাথে আছে: ${data.mobile}`);
    }
    if (data.username) {
      const { data: dupUsername } = await supabaseAdmin
        .from("profiles")
        .select("id")
        .eq("username", data.username)
        .maybeSingle();
      if (dupUsername) throw new Error(`এই username ইতিমধ্যে নেওয়া আছে: ${data.username}`);
    }

    const { data: created, error: createErr } = await supabaseAdmin.auth.admin.createUser({
      email: data.email,
      password: data.password,
      email_confirm: true,
      user_metadata: { full_name: data.full_name },
    });

    if (createErr || !created.user) {
      throw new Error(createErr?.message || "Failed to create user");
    }

    const newUserId = created.user.id;

    // Rollback helper — delete the auth.users row if anything below fails so we
    // never leave an "orphan" user that can sign in but has no role/profile.
    const rollback = async (reason: string) => {
      console.error(`[createUserFn] rolling back ${newUserId}: ${reason}`);
      try {
        await supabaseAdmin.auth.admin.deleteUser(newUserId);
      } catch (e) {
        console.error("[createUserFn] rollback failed:", e);
      }
    };

    const { error: profileErr } = await supabaseAdmin
      .from("profiles")
      .upsert(
        {
          id: newUserId,
          full_name: data.full_name,
          mobile: data.mobile || null,
          username: data.username || null,
          branch_id: data.branch_id || null,
          custom_role_id: data.custom_role_id || null,
          status: "active",
        },
        { onConflict: "id" }
      );
    if (profileErr) {
      await rollback(`profile upsert failed: ${profileErr.message}`);
      throw new Error(`Profile creation failed: ${profileErr.message}`);
    }

    // Use upsert on user_roles to avoid duplicate-key crash if a trigger or
    // earlier run already created the row.
    const { data: insertedRole, error: roleErr2 } = await supabaseAdmin
      .from("user_roles")
      .upsert(
        { user_id: newUserId, role: data.system_role },
        { onConflict: "user_id,role" }
      )
      .select("id, role")
      .single();
    if (roleErr2) {
      await rollback(`role insert failed: ${roleErr2.message}`);
      throw new Error(`Role assignment failed: ${roleErr2.message}`);
    }

    if (data.staff_record) {
      const { error: staffErr } = await supabaseAdmin.from("staff").insert({
        name: data.staff_record.name,
        mobile: data.staff_record.mobile || data.mobile || "",
        email: data.staff_record.email || data.email,
        address: data.staff_record.address || "",
        role: data.staff_record.role || "sales",
        designation: data.staff_record.designation || "",
        nid: data.staff_record.nid || "",
        username: data.staff_record.username || data.username || null,
        joining_date: data.staff_record.joining_date || null,
        salary: data.staff_record.salary || 0,
        commission_rate: data.staff_record.commission_rate || 0,
        status: data.staff_record.status || "active",
        note: data.staff_record.note || "",
        branch_id: data.staff_record.branch_id || data.branch_id || null,
        department_id: data.staff_record.department_id || null,
        photo_url: data.staff_record.photo_url || "",
        created_by: context.userId,
      });

      if (staffErr) {
        await rollback(`staff insert failed: ${staffErr.message}`);
        throw new Error(`Staff record creation failed: ${staffErr.message}`);
      }
    }

    return {
      id: newUserId,
      email: data.email,
      full_name: data.full_name,
      mobile: data.mobile || "",
      username: data.username || "",
      branch_id: data.branch_id || null,
      custom_role_id: data.custom_role_id || null,
      status: "active",
      created_at: created.user.created_at ?? new Date().toISOString(),
      last_login: null,
      email_confirmed_at: created.user.email_confirmed_at ?? null,
      roles: insertedRole ? [insertedRole] : [],
    };
  });

export const deleteUserFn = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: unknown) =>
    z.object({ user_id: z.string().uuid() }).parse(input)
  )
  .handler(async ({ data, context }) => {
    const { data: isAdminRow } = await context.supabase
      .from("user_roles")
      .select("role")
      .eq("user_id", context.userId)
      .eq("role", "admin")
      .maybeSingle();

    if (!isAdminRow) throw new Error("Only admins can delete users");
    if (data.user_id === context.userId) throw new Error("You cannot delete your own account");

    const { error } = await supabaseAdmin.auth.admin.deleteUser(data.user_id);
    if (error) throw new Error(error.message);
    return { ok: true };
  });

export const resetUserPasswordFn = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: unknown) =>
    z
      .object({
        user_id: z.string().uuid(),
        new_password: z.string().min(6).max(128),
      })
      .parse(input)
  )
  .handler(async ({ data, context }) => {
    const { data: isAdminRow } = await context.supabase
      .from("user_roles")
      .select("role")
      .eq("user_id", context.userId)
      .eq("role", "admin")
      .maybeSingle();

    if (!isAdminRow) throw new Error("Only admins can reset passwords");

    const { error } = await supabaseAdmin.auth.admin.updateUserById(data.user_id, {
      password: data.new_password,
    });
    if (error) throw new Error(error.message);
    return { ok: true };
  });
