import { auditLog, db } from '@sim/db'
import { user } from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { eq } from 'drizzle-orm'
import { getClientIp } from '@/lib/core/utils/request'
import { generateShortId } from '@/lib/core/utils/uuid'

const logger = createLogger('AuditLog')

/**
 * All auditable actions in the platform, grouped by resource type.
 */
export const AuditAction = {
  // API Keys
  API_KEY_CREATED: 'api_key.created',
  API_KEY_UPDATED: 'api_key.updated',
  API_KEY_REVOKED: 'api_key.revoked',
  PERSONAL_API_KEY_CREATED: 'personal_api_key.created',
  PERSONAL_API_KEY_REVOKED: 'personal_api_key.revoked',

  // BYOK Keys
  BYOK_KEY_CREATED: 'byok_key.created',
  BYOK_KEY_DELETED: 'byok_key.deleted',

  // Chat
  CHAT_DEPLOYED: 'chat.deployed',
  CHAT_UPDATED: 'chat.updated',
  CHAT_DELETED: 'chat.deleted',

  // Custom Tools
  CUSTOM_TOOL_CREATED: 'custom_tool.created',
  CUSTOM_TOOL_UPDATED: 'custom_tool.updated',
  CUSTOM_TOOL_DELETED: 'custom_tool.deleted',

  // Billing
  CREDIT_PURCHASED: 'credit.purchased',

  // Credential Sets
  CREDENTIAL_SET_CREATED: 'credential_set.created',
  CREDENTIAL_SET_UPDATED: 'credential_set.updated',
  CREDENTIAL_SET_DELETED: 'credential_set.deleted',
  CREDENTIAL_SET_MEMBER_REMOVED: 'credential_set_member.removed',
  CREDENTIAL_SET_MEMBER_LEFT: 'credential_set_member.left',
  CREDENTIAL_SET_INVITATION_CREATED: 'credential_set_invitation.created',
  CREDENTIAL_SET_INVITATION_ACCEPTED: 'credential_set_invitation.accepted',
  CREDENTIAL_SET_INVITATION_RESENT: 'credential_set_invitation.resent',
  CREDENTIAL_SET_INVITATION_REVOKED: 'credential_set_invitation.revoked',

  // Connector Documents
  CONNECTOR_DOCUMENT_RESTORED: 'connector_document.restored',
  CONNECTOR_DOCUMENT_EXCLUDED: 'connector_document.excluded',

  // Documents
  DOCUMENT_UPLOADED: 'document.uploaded',
  DOCUMENT_UPDATED: 'document.updated',
  DOCUMENT_DELETED: 'document.deleted',

  // Environment
  ENVIRONMENT_UPDATED: 'environment.updated',

  // Files
  FILE_UPLOADED: 'file.uploaded',
  FILE_UPDATED: 'file.updated',
  FILE_DELETED: 'file.deleted',
  FILE_RESTORED: 'file.restored',

  // Folders
  FOLDER_CREATED: 'folder.created',
  FOLDER_DELETED: 'folder.deleted',
  FOLDER_DUPLICATED: 'folder.duplicated',
  FOLDER_RESTORED: 'folder.restored',

  // Forms
  FORM_CREATED: 'form.created',
  FORM_UPDATED: 'form.updated',
  FORM_DELETED: 'form.deleted',

  // Invitations
  INVITATION_ACCEPTED: 'invitation.accepted',
  INVITATION_REVOKED: 'invitation.revoked',

  // Knowledge Base Connectors
  CONNECTOR_CREATED: 'connector.created',
  CONNECTOR_UPDATED: 'connector.updated',
  CONNECTOR_DELETED: 'connector.deleted',
  CONNECTOR_SYNCED: 'connector.synced',

  // Knowledge Bases
  KNOWLEDGE_BASE_CREATED: 'knowledge_base.created',
  KNOWLEDGE_BASE_UPDATED: 'knowledge_base.updated',
  KNOWLEDGE_BASE_DELETED: 'knowledge_base.deleted',
  KNOWLEDGE_BASE_RESTORED: 'knowledge_base.restored',

  // MCP Servers
  MCP_SERVER_ADDED: 'mcp_server.added',
  MCP_SERVER_UPDATED: 'mcp_server.updated',
  MCP_SERVER_REMOVED: 'mcp_server.removed',

  // Members
  MEMBER_INVITED: 'member.invited',
  MEMBER_REMOVED: 'member.removed',
  MEMBER_ROLE_CHANGED: 'member.role_changed',

  // Notifications
  NOTIFICATION_CREATED: 'notification.created',
  NOTIFICATION_UPDATED: 'notification.updated',
  NOTIFICATION_DELETED: 'notification.deleted',

  // OAuth / Credentials
  OAUTH_DISCONNECTED: 'oauth.disconnected',
  CREDENTIAL_RENAMED: 'credential.renamed',
  CREDENTIAL_DELETED: 'credential.deleted',

  // Password
  PASSWORD_RESET: 'password.reset',

  // Organizations
  ORGANIZATION_CREATED: 'organization.created',
  ORGANIZATION_UPDATED: 'organization.updated',
  ORG_MEMBER_ADDED: 'org_member.added',
  ORG_MEMBER_REMOVED: 'org_member.removed',
  ORG_MEMBER_ROLE_CHANGED: 'org_member.role_changed',
  ORG_INVITATION_CREATED: 'org_invitation.created',
  ORG_INVITATION_ACCEPTED: 'org_invitation.accepted',
  ORG_INVITATION_REJECTED: 'org_invitation.rejected',
  ORG_INVITATION_CANCELLED: 'org_invitation.cancelled',
  ORG_INVITATION_REVOKED: 'org_invitation.revoked',

  // Permission Groups
  PERMISSION_GROUP_CREATED: 'permission_group.created',
  PERMISSION_GROUP_UPDATED: 'permission_group.updated',
  PERMISSION_GROUP_DELETED: 'permission_group.deleted',
  PERMISSION_GROUP_MEMBER_ADDED: 'permission_group_member.added',
  PERMISSION_GROUP_MEMBER_REMOVED: 'permission_group_member.removed',

  // Skills
  SKILL_CREATED: 'skill.created',
  SKILL_UPDATED: 'skill.updated',
  SKILL_DELETED: 'skill.deleted',

  // Schedules
  SCHEDULE_UPDATED: 'schedule.updated',

  // Tables
  TABLE_CREATED: 'table.created',
  TABLE_UPDATED: 'table.updated',
  TABLE_DELETED: 'table.deleted',
  TABLE_RESTORED: 'table.restored',

  // Templates
  TEMPLATE_CREATED: 'template.created',
  TEMPLATE_UPDATED: 'template.updated',
  TEMPLATE_DELETED: 'template.deleted',

  // Webhooks
  WEBHOOK_CREATED: 'webhook.created',
  WEBHOOK_DELETED: 'webhook.deleted',

  // Workflows
  WORKFLOW_CREATED: 'workflow.created',
  WORKFLOW_DELETED: 'workflow.deleted',
  WORKFLOW_RESTORED: 'workflow.restored',
  WORKFLOW_DEPLOYED: 'workflow.deployed',
  WORKFLOW_UNDEPLOYED: 'workflow.undeployed',
  WORKFLOW_DUPLICATED: 'workflow.duplicated',
  WORKFLOW_DEPLOYMENT_ACTIVATED: 'workflow.deployment_activated',
  WORKFLOW_DEPLOYMENT_REVERTED: 'workflow.deployment_reverted',
  WORKFLOW_LOCKED: 'workflow.locked',
  WORKFLOW_UNLOCKED: 'workflow.unlocked',
  WORKFLOW_VARIABLES_UPDATED: 'workflow.variables_updated',

  // Workspaces
  WORKSPACE_CREATED: 'workspace.created',
  WORKSPACE_DELETED: 'workspace.deleted',
  WORKSPACE_DUPLICATED: 'workspace.duplicated',
} as const

export type AuditActionType = (typeof AuditAction)[keyof typeof AuditAction]

/**
 * All resource types that can appear in audit log entries.
 */
export const AuditResourceType = {
  API_KEY: 'api_key',
  BILLING: 'billing',
  BYOK_KEY: 'byok_key',
  CHAT: 'chat',
  CONNECTOR: 'connector',
  CREDENTIAL_SET: 'credential_set',
  CUSTOM_TOOL: 'custom_tool',
  DOCUMENT: 'document',
  ENVIRONMENT: 'environment',
  FILE: 'file',
  FOLDER: 'folder',
  FORM: 'form',
  KNOWLEDGE_BASE: 'knowledge_base',
  MCP_SERVER: 'mcp_server',
  NOTIFICATION: 'notification',
  OAUTH: 'oauth',
  ORGANIZATION: 'organization',
  PASSWORD: 'password',
  PERMISSION_GROUP: 'permission_group',
  SCHEDULE: 'schedule',
  SKILL: 'skill',
  TABLE: 'table',
  TEMPLATE: 'template',
  WEBHOOK: 'webhook',
  WORKFLOW: 'workflow',
  WORKSPACE: 'workspace',
} as const

export type AuditResourceTypeValue = (typeof AuditResourceType)[keyof typeof AuditResourceType]

interface AuditLogParams {
  workspaceId?: string | null
  actorId: string
  action: AuditActionType
  resourceType: AuditResourceTypeValue
  resourceId?: string
  actorName?: string | null
  actorEmail?: string | null
  resourceName?: string
  description?: string
  metadata?: Record<string, unknown>
  request?: Request
}

/**
 * Records an audit log entry. Fire-and-forget — never throws or blocks the caller.
 * If actorName and actorEmail are both undefined (not provided by the caller),
 * resolves them from the user table before inserting.
 */
export function recordAudit(params: AuditLogParams): void {
  insertAuditLog(params).catch((error) => {
    logger.error('Failed to record audit log', { error, action: params.action })
  })
}

async function insertAuditLog(params: AuditLogParams): Promise<void> {
  const ipAddress = params.request ? getClientIp(params.request) : undefined
  const userAgent = params.request?.headers.get('user-agent') ?? undefined

  let { actorName, actorEmail } = params

  if (actorName === undefined && actorEmail === undefined && params.actorId) {
    try {
      const [row] = await db
        .select({ name: user.name, email: user.email })
        .from(user)
        .where(eq(user.id, params.actorId))
        .limit(1)
      actorName = row?.name ?? undefined
      actorEmail = row?.email ?? undefined
    } catch (error) {
      logger.warn('Failed to resolve actor info', { error, actorId: params.actorId })
    }
  }

  await db.insert(auditLog).values({
    id: generateShortId(),
    workspaceId: params.workspaceId || null,
    actorId: params.actorId,
    action: params.action,
    resourceType: params.resourceType,
    resourceId: params.resourceId,
    actorName: actorName ?? undefined,
    actorEmail: actorEmail ?? undefined,
    resourceName: params.resourceName,
    description: params.description,
    metadata: params.metadata ?? {},
    ipAddress,
    userAgent,
  })
}
