import "server-only"

import { count, desc, eq } from "drizzle-orm"

import { db } from "@/shared/db"
import { aiProviders, passwordSecurity, users } from "@/shared/db/schema"

import type { AiProviderExisting, AiProviderName, AiProviderSummary } from "./types"

// --- AI Provider operations ---

export async function getAiProviderSummaries(): Promise<AiProviderSummary[]> {
  const rows = await db
    .select({
      id: aiProviders.id,
      provider: aiProviders.provider,
      baseUrl: aiProviders.baseUrl,
      model: aiProviders.model,
      apiKeyLast4: aiProviders.apiKeyLast4,
      isDefault: aiProviders.isDefault,
      updatedAt: aiProviders.updatedAt,
    })
    .from(aiProviders)
    .orderBy(desc(aiProviders.updatedAt))
  return rows
}

export async function countDefaultAiProviders(): Promise<number> {
  const [row] = await db
    .select({ value: count() })
    .from(aiProviders)
    .where(eq(aiProviders.isDefault, true))
  return Number(row?.value ?? 0)
}

export async function getAiProviderForUpdate(id: string): Promise<AiProviderExisting | null> {
  const [row] = await db
    .select({
      id: aiProviders.id,
      apiKeyEncrypted: aiProviders.apiKeyEncrypted,
      apiKeyLast4: aiProviders.apiKeyLast4,
      isDefault: aiProviders.isDefault,
    })
    .from(aiProviders)
    .where(eq(aiProviders.id, id))
    .limit(1)
  return row ?? null
}

export async function updateAiProvider(
  id: string,
  data: {
    provider: AiProviderName
    baseUrl: string | null
    model: string
    apiKeyEncrypted: string
    apiKeyLast4: string | null
    isDefault: boolean
    updatedBy: string
  },
  resetOtherDefaults: boolean
): Promise<void> {
  await db.transaction(async (tx) => {
    if (resetOtherDefaults) {
      await tx.update(aiProviders).set({ isDefault: false }).where(eq(aiProviders.isDefault, true))
    }
    await tx
      .update(aiProviders)
      .set({
        provider: data.provider,
        baseUrl: data.baseUrl,
        model: data.model,
        apiKeyEncrypted: data.apiKeyEncrypted,
        apiKeyLast4: data.apiKeyLast4,
        isDefault: data.isDefault,
        updatedBy: data.updatedBy,
      })
      .where(eq(aiProviders.id, id))
  })
}

export async function createAiProvider(
  data: {
    id: string
    provider: AiProviderName
    baseUrl: string | null
    model: string
    apiKeyEncrypted: string
    apiKeyLast4: string | null
    isDefault: boolean
    createdBy: string
    updatedBy: string
  },
  resetOtherDefaults: boolean
): Promise<void> {
  await db.transaction(async (tx) => {
    if (resetOtherDefaults) {
      await tx.update(aiProviders).set({ isDefault: false }).where(eq(aiProviders.isDefault, true))
    }
    await tx.insert(aiProviders).values({
      id: data.id,
      provider: data.provider,
      baseUrl: data.baseUrl,
      model: data.model,
      apiKeyEncrypted: data.apiKeyEncrypted,
      apiKeyLast4: data.apiKeyLast4,
      isDefault: data.isDefault,
      createdBy: data.createdBy,
      updatedBy: data.updatedBy,
    })
  })
}

// --- Password change operations ---

export async function getUserPasswordHash(
  userId: string
): Promise<{ password: string | null } | null> {
  const [row] = await db
    .select({ password: users.password })
    .from(users)
    .where(eq(users.id, userId))
    .limit(1)
  return row ?? null
}

export async function getPasswordSecurityByUserId(
  userId: string
): Promise<{ id: string } | null> {
  const [row] = await db
    .select({ id: passwordSecurity.id })
    .from(passwordSecurity)
    .where(eq(passwordSecurity.userId, userId))
    .limit(1)
  return row ?? null
}

export async function updateUserPassword(
  userId: string,
  newHash: string,
  now: Date
): Promise<void> {
  await db
    .update(users)
    .set({ password: newHash, updatedAt: now })
    .where(eq(users.id, userId))
}

export async function upsertPasswordSecurityOnPasswordChange(
  userId: string,
  now: Date,
  existing: { id: string } | null
): Promise<void> {
  if (existing) {
    await db
      .update(passwordSecurity)
      .set({
        lastPasswordChange: now,
        passwordChangedAt: now,
        mustChangePassword: false,
        updatedAt: now,
      })
      .where(eq(passwordSecurity.userId, userId))
  } else {
    await db.insert(passwordSecurity).values({
      userId,
      lastPasswordChange: now,
      passwordChangedAt: now,
      mustChangePassword: false,
    })
  }
}
