import { mutation, query } from "./_generated/server"
import type { MutationCtx, QueryCtx } from "./_generated/server"
import { ConvexError, v } from "convex/values"
import type { Id } from "./_generated/dataModel"

import { requireAdmin } from "./rbac"
import { getTemplateByKey, normalizeFormTemplateKey } from "./ticketFormTemplates"
import { TICKET_FORM_CONFIG } from "./ticketForms.config"

const VALID_SCOPES = new Set(["tenant", "company", "user"])

function normalizeScope(input: string) {
  const normalized = input.trim().toLowerCase()
  if (!VALID_SCOPES.has(normalized)) {
    throw new ConvexError("Escopo inválido")
  }
  return normalized
}

async function ensureTemplateExists(ctx: MutationCtx | QueryCtx, tenantId: string, template: string) {
  const normalized = normalizeFormTemplateKey(template)
  if (!normalized) {
    throw new ConvexError("Template desconhecido")
  }
  const existing = await getTemplateByKey(ctx, tenantId, normalized)
  if (existing && existing.isArchived !== true) {
    return normalized
  }
  const fallback = TICKET_FORM_CONFIG.find((tpl) => tpl.key === normalized)
  if (fallback) {
    return normalized
  }
  throw new ConvexError("Template desconhecido")
}

export const list = query({
  args: {
    tenantId: v.string(),
    viewerId: v.id("users"),
    template: v.optional(v.string()),
  },
  handler: async (ctx, { tenantId, viewerId, template }) => {
    await requireAdmin(ctx, viewerId, tenantId)
    const normalizedTemplate = template ? normalizeFormTemplateKey(template) : null
    const settings = await ctx.db
      .query("ticketFormSettings")
      .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
      .take(100)
    return settings
      .filter((setting) => !normalizedTemplate || setting.template === normalizedTemplate)
      .map((setting) => ({
        id: setting._id,
        template: setting.template,
        scope: setting.scope,
        companyId: setting.companyId ?? null,
        userId: setting.userId ?? null,
        enabled: setting.enabled,
        createdAt: setting.createdAt,
        updatedAt: setting.updatedAt,
        actorId: setting.actorId ?? null,
      }))
  },
})

export const upsert = mutation({
  args: {
    tenantId: v.string(),
    actorId: v.id("users"),
    template: v.string(),
    scope: v.string(),
    companyId: v.optional(v.id("companies")),
    userId: v.optional(v.id("users")),
    enabled: v.boolean(),
  },
  handler: async (ctx, { tenantId, actorId, template, scope, companyId, userId, enabled }) => {
    await requireAdmin(ctx, actorId, tenantId)
    const normalizedTemplate = await ensureTemplateExists(ctx, tenantId, template)
    const normalizedScope = normalizeScope(scope)

    if (normalizedScope === "company" && !companyId) {
      throw new ConvexError("Informe a empresa para configurar o template")
    }
    if (normalizedScope === "user" && !userId) {
      throw new ConvexError("Informe o usuário para configurar o template")
    }
    if (normalizedScope === "tenant") {
      if (companyId || userId) {
        throw new ConvexError("Escopo global não aceita empresa ou usuário")
      }
    }

    const existing = await findExisting(ctx, tenantId, normalizedTemplate, normalizedScope, companyId, userId)
    const now = Date.now()
    if (existing) {
      await ctx.db.patch(existing._id, {
        enabled,
        updatedAt: now,
        actorId,
      })
      return existing._id
    }

    const id = await ctx.db.insert("ticketFormSettings", {
      tenantId,
      template: normalizedTemplate,
      scope: normalizedScope,
      companyId: normalizedScope === "company" ? (companyId as Id<"companies">) : undefined,
      userId: normalizedScope === "user" ? (userId as Id<"users">) : undefined,
      enabled,
      createdAt: now,
      updatedAt: now,
      actorId,
    })
    return id
  },
})

export const remove = mutation({
  args: {
    tenantId: v.string(),
    actorId: v.id("users"),
    settingId: v.id("ticketFormSettings"),
  },
  handler: async (ctx, { tenantId, actorId, settingId }) => {
    await requireAdmin(ctx, actorId, tenantId)
    const setting = await ctx.db.get(settingId)
    if (!setting || setting.tenantId !== tenantId) {
      throw new ConvexError("Configuração não encontrada")
    }
    await ctx.db.delete(settingId)
    return { ok: true }
  },
})

async function findExisting(
  ctx: MutationCtx | QueryCtx,
  tenantId: string,
  template: string,
  scope: string,
  companyId?: Id<"companies">,
  userId?: Id<"users">,
) {
  const candidates = await ctx.db
    .query("ticketFormSettings")
    .withIndex("by_tenant_template_scope", (q) => q.eq("tenantId", tenantId).eq("template", template).eq("scope", scope))
    .take(100)

  return candidates.find((setting) => {
    if (scope === "tenant") return true
    if (scope === "company") {
      return setting.companyId && companyId && String(setting.companyId) === String(companyId)
    }
    if (scope === "user") {
      return setting.userId && userId && String(setting.userId) === String(userId)
    }
    return false
  }) ?? null
}
