import { workAppSlackChannelAgentConfigs, workAppSlackUserMappings, workAppSlackWorkspaces } from "../../db/runtime/runtime-schema.js";
import { projectScopedWhere, tenantScopedWhere } from "../manage/scope-helpers.js";
import { and, eq } from "drizzle-orm";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { nanoid } from "nanoid";

//#region src/data-access/runtime/workAppSlack.ts
const DEFAULT_CLIENT_ID = "work-apps-slack";
const createWorkAppSlackWorkspace = (db) => async (data) => {
	const id = `wsw_${nanoid(21)}`;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [result] = await db.insert(workAppSlackWorkspaces).values({
		id,
		...data,
		createdAt: now,
		updatedAt: now
	}).returning();
	return result;
};
const findWorkAppSlackWorkspaceByTeamId = (db) => async (tenantId, slackTeamId) => {
	return (await db.select().from(workAppSlackWorkspaces).where(and(tenantScopedWhere(workAppSlackWorkspaces, { tenantId }), eq(workAppSlackWorkspaces.slackTeamId, slackTeamId))).limit(1))[0] || null;
};
/**
* Find a workspace by Slack team ID only (without tenant filter).
* Slack team IDs are globally unique, so this is safe for resolving
* the tenant from an incoming Slack event where tenant is unknown.
*/
const findWorkAppSlackWorkspaceBySlackTeamId = (db) => async (slackTeamId) => {
	return (await db.select().from(workAppSlackWorkspaces).where(eq(workAppSlackWorkspaces.slackTeamId, slackTeamId)).limit(1))[0] || null;
};
/**
* Find a workspace by its Nango connection ID.
*
* One Nango connection = one OAuth token = one Slack workspace.
* The nangoConnectionId should be globally unique (not per-tenant).
* The schema has a unique constraint on nangoConnectionId ensuring this.
*/
const findWorkAppSlackWorkspaceByNangoConnectionId = (db) => async (nangoConnectionId) => {
	return (await db.select().from(workAppSlackWorkspaces).where(eq(workAppSlackWorkspaces.nangoConnectionId, nangoConnectionId)))[0] || null;
};
const listWorkAppSlackWorkspacesByTenant = (db) => async (tenantId) => {
	return db.select().from(workAppSlackWorkspaces).where(tenantScopedWhere(workAppSlackWorkspaces, { tenantId }));
};
const updateWorkAppSlackWorkspace = (db) => async (id, data) => {
	const [result] = await db.update(workAppSlackWorkspaces).set({
		...data,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	}).where(eq(workAppSlackWorkspaces.id, id)).returning();
	return result || null;
};
const deleteWorkAppSlackWorkspace = (db) => async (id) => {
	return (await db.delete(workAppSlackWorkspaces).where(eq(workAppSlackWorkspaces.id, id)).returning()).length > 0;
};
const deleteWorkAppSlackWorkspaceByNangoConnectionId = (db) => async (nangoConnectionId) => {
	return (await db.delete(workAppSlackWorkspaces).where(eq(workAppSlackWorkspaces.nangoConnectionId, nangoConnectionId)).returning()).length > 0;
};
const findWorkAppSlackUserMapping = (db) => async (tenantId, slackUserId, slackTeamId, clientId = DEFAULT_CLIENT_ID) => {
	return (await db.select().from(workAppSlackUserMappings).where(and(tenantScopedWhere(workAppSlackUserMappings, { tenantId }), eq(workAppSlackUserMappings.clientId, clientId), eq(workAppSlackUserMappings.slackUserId, slackUserId), eq(workAppSlackUserMappings.slackTeamId, slackTeamId))).limit(1))[0] || null;
};
const findWorkAppSlackUserMappingByInkeepUserId = (db) => async (inkeepUserId) => {
	return db.select().from(workAppSlackUserMappings).where(eq(workAppSlackUserMappings.inkeepUserId, inkeepUserId));
};
/**
* Find a user mapping by Slack user ID and team ID only (ignores tenant).
* Use this when you need to find the user's tenant from their mapping.
*/
const findWorkAppSlackUserMappingBySlackUser = (db) => async (slackUserId, slackTeamId, clientId = DEFAULT_CLIENT_ID) => {
	return (await db.select().from(workAppSlackUserMappings).where(and(eq(workAppSlackUserMappings.clientId, clientId), eq(workAppSlackUserMappings.slackUserId, slackUserId), eq(workAppSlackUserMappings.slackTeamId, slackTeamId))).limit(1))[0] || null;
};
const listWorkAppSlackUserMappingsByTeam = (db) => async (tenantId, slackTeamId) => {
	return db.select().from(workAppSlackUserMappings).where(and(tenantScopedWhere(workAppSlackUserMappings, { tenantId }), eq(workAppSlackUserMappings.slackTeamId, slackTeamId)));
};
const createWorkAppSlackUserMapping = (db) => async (data) => {
	const id = `wsum_${nanoid(21)}`;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [result] = await db.insert(workAppSlackUserMappings).values({
		id,
		clientId: data.clientId || DEFAULT_CLIENT_ID,
		...data,
		linkedAt: now,
		createdAt: now,
		updatedAt: now
	}).returning();
	return result;
};
const deleteWorkAppSlackUserMapping = (db) => async (tenantId, slackUserId, slackTeamId, clientId = DEFAULT_CLIENT_ID) => {
	return (await db.delete(workAppSlackUserMappings).where(and(tenantScopedWhere(workAppSlackUserMappings, { tenantId }), eq(workAppSlackUserMappings.clientId, clientId), eq(workAppSlackUserMappings.slackUserId, slackUserId), eq(workAppSlackUserMappings.slackTeamId, slackTeamId))).returning()).length > 0;
};
const deleteAllWorkAppSlackUserMappingsByTeam = (db) => async (tenantId, slackTeamId, clientId = DEFAULT_CLIENT_ID) => {
	return (await db.delete(workAppSlackUserMappings).where(and(tenantScopedWhere(workAppSlackUserMappings, { tenantId }), eq(workAppSlackUserMappings.clientId, clientId), eq(workAppSlackUserMappings.slackTeamId, slackTeamId))).returning()).length;
};
const createWorkAppSlackChannelAgentConfig = (db) => async (data) => {
	const id = `wscac_${nanoid(21)}`;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [result] = await db.insert(workAppSlackChannelAgentConfigs).values({
		id,
		...data,
		createdAt: now,
		updatedAt: now
	}).returning();
	return result;
};
const findWorkAppSlackChannelAgentConfig = (db) => async (tenantId, slackTeamId, slackChannelId) => {
	return (await db.select().from(workAppSlackChannelAgentConfigs).where(and(tenantScopedWhere(workAppSlackChannelAgentConfigs, { tenantId }), eq(workAppSlackChannelAgentConfigs.slackTeamId, slackTeamId), eq(workAppSlackChannelAgentConfigs.slackChannelId, slackChannelId))).limit(1))[0] || null;
};
const listWorkAppSlackChannelAgentConfigsByTeam = (db) => async (tenantId, slackTeamId) => {
	return db.select().from(workAppSlackChannelAgentConfigs).where(and(tenantScopedWhere(workAppSlackChannelAgentConfigs, { tenantId }), eq(workAppSlackChannelAgentConfigs.slackTeamId, slackTeamId)));
};
/**
* Atomic upsert using onConflictDoUpdate to avoid TOCTOU race conditions.
* Uses the unique constraint on (tenantId, slackTeamId, slackChannelId).
*/
const upsertWorkAppSlackChannelAgentConfig = (db) => async (data) => {
	const id = `wscac_${nanoid(21)}`;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [result] = await db.insert(workAppSlackChannelAgentConfigs).values({
		id,
		...data,
		createdAt: now,
		updatedAt: now
	}).onConflictDoUpdate({
		target: [
			workAppSlackChannelAgentConfigs.tenantId,
			workAppSlackChannelAgentConfigs.slackTeamId,
			workAppSlackChannelAgentConfigs.slackChannelId
		],
		set: {
			projectId: data.projectId,
			agentId: data.agentId,
			slackChannelName: data.slackChannelName,
			slackChannelType: data.slackChannelType,
			enabled: data.enabled,
			grantAccessToMembers: data.grantAccessToMembers,
			configuredByUserId: data.configuredByUserId,
			updatedAt: now
		}
	}).returning();
	return result;
};
const deleteWorkAppSlackChannelAgentConfig = (db) => async (tenantId, slackTeamId, slackChannelId) => {
	return (await db.delete(workAppSlackChannelAgentConfigs).where(and(tenantScopedWhere(workAppSlackChannelAgentConfigs, { tenantId }), eq(workAppSlackChannelAgentConfigs.slackTeamId, slackTeamId), eq(workAppSlackChannelAgentConfigs.slackChannelId, slackChannelId))).returning()).length > 0;
};
const deleteAllWorkAppSlackChannelAgentConfigsByTeam = (db) => async (tenantId, slackTeamId) => {
	return (await db.delete(workAppSlackChannelAgentConfigs).where(and(tenantScopedWhere(workAppSlackChannelAgentConfigs, { tenantId }), eq(workAppSlackChannelAgentConfigs.slackTeamId, slackTeamId))).returning()).length;
};
const deleteWorkAppSlackChannelAgentConfigsByAgent = (db) => async (tenantId, projectId, agentId) => {
	return (await db.delete(workAppSlackChannelAgentConfigs).where(and(projectScopedWhere(workAppSlackChannelAgentConfigs, {
		tenantId,
		projectId
	}), eq(workAppSlackChannelAgentConfigs.agentId, agentId))).returning()).length;
};
const deleteWorkAppSlackChannelAgentConfigsByProject = (db) => async (tenantId, projectId) => {
	return (await db.delete(workAppSlackChannelAgentConfigs).where(projectScopedWhere(workAppSlackChannelAgentConfigs, {
		tenantId,
		projectId
	})).returning()).length;
};
const clearWorkspaceDefaultsByAgent = (db) => async (tenantId, projectId, agentId) => {
	return (await db.update(workAppSlackWorkspaces).set({
		defaultAgentId: null,
		defaultProjectId: null,
		defaultGrantAccessToMembers: null,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	}).where(and(tenantScopedWhere(workAppSlackWorkspaces, { tenantId }), eq(workAppSlackWorkspaces.defaultProjectId, projectId), eq(workAppSlackWorkspaces.defaultAgentId, agentId))).returning()).length;
};
const clearWorkspaceDefaultsByProject = (db) => async (tenantId, projectId) => {
	return (await db.update(workAppSlackWorkspaces).set({
		defaultAgentId: null,
		defaultProjectId: null,
		defaultGrantAccessToMembers: null,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	}).where(and(tenantScopedWhere(workAppSlackWorkspaces, { tenantId }), eq(workAppSlackWorkspaces.defaultProjectId, projectId))).returning()).length;
};
const DEV_CONFIG_FILENAME = ".slack-dev.json";
function findSlackDevConfigPath() {
	if (process.env.ENVIRONMENT !== "development") return null;
	let dir = process.cwd();
	while (true) {
		const candidate = join(dir, DEV_CONFIG_FILENAME);
		if (existsSync(candidate)) return candidate;
		const parent = dirname(dir);
		if (parent === dir) break;
		dir = parent;
	}
	return null;
}
function clearDevConfigWorkspaceDefaultsByAgent(projectId, agentId) {
	const configPath = findSlackDevConfigPath();
	if (!configPath) return;
	try {
		const config = JSON.parse(readFileSync(configPath, "utf-8"));
		if (!config?.metadata?.default_agent) return;
		const defaultAgent = JSON.parse(config.metadata.default_agent);
		if (defaultAgent.agentId === agentId && defaultAgent.projectId === projectId) {
			config.metadata.default_agent = "";
			writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
		}
	} catch {}
}
function clearDevConfigWorkspaceDefaultsByProject(projectId) {
	const configPath = findSlackDevConfigPath();
	if (!configPath) return;
	try {
		const config = JSON.parse(readFileSync(configPath, "utf-8"));
		if (!config?.metadata?.default_agent) return;
		if (JSON.parse(config.metadata.default_agent).projectId === projectId) {
			config.metadata.default_agent = "";
			writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
		}
	} catch {}
}

//#endregion
export { clearDevConfigWorkspaceDefaultsByAgent, clearDevConfigWorkspaceDefaultsByProject, clearWorkspaceDefaultsByAgent, clearWorkspaceDefaultsByProject, createWorkAppSlackChannelAgentConfig, createWorkAppSlackUserMapping, createWorkAppSlackWorkspace, deleteAllWorkAppSlackChannelAgentConfigsByTeam, deleteAllWorkAppSlackUserMappingsByTeam, deleteWorkAppSlackChannelAgentConfig, deleteWorkAppSlackChannelAgentConfigsByAgent, deleteWorkAppSlackChannelAgentConfigsByProject, deleteWorkAppSlackUserMapping, deleteWorkAppSlackWorkspace, deleteWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackChannelAgentConfig, findWorkAppSlackUserMapping, findWorkAppSlackUserMappingByInkeepUserId, findWorkAppSlackUserMappingBySlackUser, findWorkAppSlackWorkspaceByNangoConnectionId, findWorkAppSlackWorkspaceBySlackTeamId, findWorkAppSlackWorkspaceByTeamId, listWorkAppSlackChannelAgentConfigsByTeam, listWorkAppSlackUserMappingsByTeam, listWorkAppSlackWorkspacesByTenant, updateWorkAppSlackWorkspace, upsertWorkAppSlackChannelAgentConfig };