import { createHash, randomBytes } from "node:crypto";
import { and, eq } from "drizzle-orm";
import { cookies } from "next/headers";
import { db } from "@/db";
import { authAccounts, authSessions, authUsers, siteSettings } from "@/db/schema";

export const SESSION_COOKIE = "kiln-session";
export const STATE_COOKIE_PREFIX = "kiln-oauth-state-";

const settingDefaults = {
  auth_enabled: process.env.AUTH_ENABLED === "true",
  auth_vk_enabled: process.env.AUTH_VK_ENABLED !== "false",
  auth_yandex_enabled: process.env.AUTH_YANDEX_ENABLED !== "false",
  auth_telegram_enabled: process.env.AUTH_TELEGRAM_ENABLED !== "false",
  auth_max_enabled: process.env.AUTH_MAX_ENABLED !== "false",
  orders_enabled: process.env.ORDERS_ENABLED === "true",
  orders_pickup_enabled: process.env.ORDERS_PICKUP_ENABLED !== "false",
  orders_deferred_enabled: process.env.ORDERS_DEFERRED_ENABLED !== "false"
};
export type AuthProvider = "vk" | "yandex" | "telegram" | "max";

export async function isSettingEnabled(key: keyof typeof settingDefaults) {
  if (!db) return settingDefaults[key];
  const [row] = await db.select().from(siteSettings).where(eq(siteSettings.key, key)).limit(1);
  return row?.value ?? settingDefaults[key];
}

export function siteUrl(request?: Request) {
  if (process.env.NEXT_PUBLIC_SITE_URL) return process.env.NEXT_PUBLIC_SITE_URL.replace(/\/$/, "");
  if (request) {
    const forwardedHost = request.headers.get("x-forwarded-host")?.split(",")[0]?.trim();
    const host = forwardedHost || request.headers.get("host");
    const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
    if (host) return `${forwardedProto || new URL(request.url).protocol.replace(":", "")}://${host}`;
    return new URL(request.url).origin;
  }
  return "http://localhost:3000";
}

export function createOAuthState() { return randomBytes(24).toString("hex"); }
export function hashToken(token: string) { return createHash("sha256").update(token).digest("hex"); }

export async function createSession(userId: number) {
  if (!db) throw new Error("Database is not configured");
  const token = randomBytes(32).toString("base64url");
  await db.insert(authSessions).values({ tokenHash: hashToken(token), userId, expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) });
  return token;
}

export async function currentUser() {
  if (!db) return null;
  const token = (await cookies()).get(SESSION_COOKIE)?.value;
  if (!token) return null;
  const [row] = await db.select({ session: authSessions, user: authUsers }).from(authSessions).innerJoin(authUsers, eq(authUsers.id, authSessions.userId)).where(eq(authSessions.tokenHash, hashToken(token))).limit(1);
  if (!row || row.session.expiresAt < new Date()) return null;
  return row.user;
}

export async function getOrCreateUser(provider: AuthProvider, providerAccountId: string, profile: { email?: string | null; displayName: string; avatarUrl?: string | null }) {
  if (!db) throw new Error("Database is not configured");
  const [account] = await db.select().from(authAccounts).where(and(eq(authAccounts.provider, provider), eq(authAccounts.providerAccountId, providerAccountId))).limit(1);
  if (account) {
    const [user] = await db.update(authUsers).set({ email: profile.email || undefined, displayName: profile.displayName, avatarUrl: profile.avatarUrl || undefined, updatedAt: new Date() }).where(eq(authUsers.id, account.userId)).returning();
    return user;
  }
  const [user] = await db.insert(authUsers).values({ email: profile.email || null, displayName: profile.displayName, avatarUrl: profile.avatarUrl || null }).returning();
  await db.insert(authAccounts).values({ userId: user.id, provider, providerAccountId });
  return user;
}
