import { eq, and, sql } from 'drizzle-orm';
import { db } from '../db';
import { serverIntegrations } from '../server/schema';
import { userIntegrations } from '../user-data/schema';
import { users } from '../auth/schema';
import type { ServerIntegrationSelect, UserIntegrationSelect } from '../types';

// ── Server Integrations ──

export async function getServerIntegrations(): Promise<ServerIntegrationSelect[]> {
  return db.select().from(serverIntegrations);
}

export async function getServerIntegration(provider: string): Promise<ServerIntegrationSelect | undefined> {
  const [row] = await db.select().from(serverIntegrations).where(eq(serverIntegrations.provider, provider));
  return row;
}

export async function upsertServerIntegration(
  provider: string,
  config: Record<string, unknown>,
  enabled = true,
): Promise<ServerIntegrationSelect> {
  const [row] = await db
    .insert(serverIntegrations)
    .values({ provider, config, enabled, updatedAt: new Date() })
    .onConflictDoUpdate({
      target: serverIntegrations.provider,
      set: { config, enabled, updatedAt: new Date() },
    })
    .returning();
  return row!;
}

export async function deleteServerIntegration(provider: string): Promise<boolean> {
  const result = await db
    .delete(serverIntegrations)
    .where(eq(serverIntegrations.provider, provider))
    .returning({ id: serverIntegrations.id });
  return result.length > 0;
}

// ── User Integrations ──

export async function getUserIntegrations(userId: number): Promise<UserIntegrationSelect[]> {
  return db.select().from(userIntegrations).where(eq(userIntegrations.userId, userId));
}

export async function getIntegrationsByProvider(provider: string): Promise<UserIntegrationSelect[]> {
  return db.select().from(userIntegrations).where(eq(userIntegrations.provider, provider));
}

export async function getUserIntegration(userId: number, provider: string): Promise<UserIntegrationSelect | undefined> {
  const [row] = await db
    .select()
    .from(userIntegrations)
    .where(and(eq(userIntegrations.userId, userId), eq(userIntegrations.provider, provider)));
  return row;
}

type UpsertUserIntegrationParams = {
  userId: number;
  provider: string;
  serverIntegrationId?: number | null;
  config: Record<string, unknown>;
};

export async function upsertUserIntegration({
  userId,
  provider,
  serverIntegrationId,
  config,
}: UpsertUserIntegrationParams): Promise<UserIntegrationSelect> {
  const [row] = await db
    .insert(userIntegrations)
    .values({ userId, provider, serverIntegrationId: serverIntegrationId ?? null, config, updatedAt: new Date() })
    .onConflictDoUpdate({
      target: [userIntegrations.userId, userIntegrations.provider],
      set: { config, serverIntegrationId: serverIntegrationId ?? null, updatedAt: new Date() },
    })
    .returning();
  return row!;
}

export async function deleteUserIntegration(userId: number, provider: string): Promise<boolean> {
  const result = await db
    .delete(userIntegrations)
    .where(and(eq(userIntegrations.userId, userId), eq(userIntegrations.provider, provider)))
    .returning({ id: userIntegrations.id });
  return result.length > 0;
}

// ── Cross-table lookup ──

type UserIntegrationWithUser = UserIntegrationSelect & {
  user: { id: number; email: string; username: string | null };
};

export async function findUserByIntegrationConfig(
  provider: string,
  configKey: string,
  configValue: string,
): Promise<UserIntegrationWithUser | undefined> {
  const [row] = await db
    .select({
      id: userIntegrations.id,
      userId: userIntegrations.userId,
      provider: userIntegrations.provider,
      serverIntegrationId: userIntegrations.serverIntegrationId,
      config: userIntegrations.config,
      createdAt: userIntegrations.createdAt,
      updatedAt: userIntegrations.updatedAt,
      user: {
        id: users.id,
        email: users.email,
        username: users.username,
      },
    })
    .from(userIntegrations)
    .innerJoin(users, eq(userIntegrations.userId, users.id))
    .where(
      and(eq(userIntegrations.provider, provider), sql`${userIntegrations.config}->>${configKey} = ${configValue}`),
    );
  return row as UserIntegrationWithUser | undefined;
}
