import sanitizeHtml from "sanitize-html"
import { ConvexError, v } from "convex/values"

import { mutation, query } from "./_generated/server"
import { requireStaff } from "./rbac"

const SANITIZE_OPTIONS: sanitizeHtml.IOptions = {
  allowedTags: [
    "p",
    "br",
    "a",
    "strong",
    "em",
    "u",
    "s",
    "blockquote",
    "ul",
    "ol",
    "li",
    "code",
    "pre",
    "span",
    "h1",
    "h2",
    "h3",
  ],
  allowedAttributes: {
    a: ["href", "name", "target", "rel"],
    span: ["style"],
    code: ["class"],
    pre: ["class"],
  },
  allowedSchemes: ["http", "https", "mailto"],
  transformTags: {
    a: sanitizeHtml.simpleTransform("a", { rel: "noopener noreferrer", target: "_blank" }, true),
  },
  allowVulnerableTags: false,
}

function sanitizeTemplateBody(body: string) {
  const sanitized = sanitizeHtml(body || "", SANITIZE_OPTIONS).trim()
  return sanitized
}

function normalizeTitle(title: string) {
  return title?.trim()
}

export const list = query({
  args: {
    tenantId: v.string(),
    viewerId: v.id("users"),
    kind: v.optional(v.string()),
  },
  handler: async (ctx, { tenantId, viewerId, kind }) => {
    await requireStaff(ctx, viewerId, tenantId)
    const normalizedKind = (kind ?? "comment").toLowerCase()
    const templates = await ctx.db
      .query("commentTemplates")
      .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
      .take(100)

    return templates
      .filter((template) => (template.kind ?? "comment") === normalizedKind)
      .sort((a, b) => a.title.localeCompare(b.title, "pt-BR", { sensitivity: "base" }))
      .map((template) => ({
        id: template._id,
        title: template.title,
        body: template.body,
        kind: template.kind ?? "comment",
        createdAt: template.createdAt,
        updatedAt: template.updatedAt,
        createdBy: template.createdBy,
        updatedBy: template.updatedBy ?? null,
      }))
  },
})

export const create = mutation({
  args: {
    tenantId: v.string(),
    actorId: v.id("users"),
    title: v.string(),
    body: v.string(),
    kind: v.optional(v.string()),
  },
  handler: async (ctx, { tenantId, actorId, title, body, kind }) => {
    await requireStaff(ctx, actorId, tenantId)
    const normalizedTitle = normalizeTitle(title)
    if (!normalizedTitle || normalizedTitle.length < 3) {
      throw new ConvexError("Informe um título válido para o template")
    }
    const sanitizedBody = sanitizeTemplateBody(body)
    if (!sanitizedBody) {
      throw new ConvexError("Informe o conteúdo do template")
    }
    const normalizedKind = (kind ?? "comment").toLowerCase()

    const existing = await ctx.db
      .query("commentTemplates")
      .withIndex("by_tenant_title", (q) => q.eq("tenantId", tenantId).eq("title", normalizedTitle))
      .first()

    if (existing && (existing.kind ?? "comment") === normalizedKind) {
      throw new ConvexError("Já existe um template com este título")
    }

    const now = Date.now()
    const id = await ctx.db.insert("commentTemplates", {
      tenantId,
      kind: normalizedKind,
      title: normalizedTitle,
      body: sanitizedBody,
      createdBy: actorId,
      updatedBy: actorId,
      createdAt: now,
      updatedAt: now,
    })

    return id
  },
})

export const update = mutation({
  args: {
    templateId: v.id("commentTemplates"),
    tenantId: v.string(),
    actorId: v.id("users"),
    title: v.string(),
    body: v.string(),
    kind: v.optional(v.string()),
  },
  handler: async (ctx, { templateId, tenantId, actorId, title, body, kind }) => {
    await requireStaff(ctx, actorId, tenantId)
    const template = await ctx.db.get(templateId)
    if (!template || template.tenantId !== tenantId) {
      throw new ConvexError("Template não encontrado")
    }

    const normalizedTitle = normalizeTitle(title)
    if (!normalizedTitle || normalizedTitle.length < 3) {
      throw new ConvexError("Informe um título válido para o template")
    }
    const sanitizedBody = sanitizeTemplateBody(body)
    if (!sanitizedBody) {
      throw new ConvexError("Informe o conteúdo do template")
    }
    const normalizedKind = (kind ?? "comment").toLowerCase()

    const duplicate = await ctx.db
      .query("commentTemplates")
      .withIndex("by_tenant_title", (q) => q.eq("tenantId", tenantId).eq("title", normalizedTitle))
      .first()
    if (duplicate && duplicate._id !== templateId && (duplicate.kind ?? "comment") === normalizedKind) {
      throw new ConvexError("Já existe um template com este título")
    }

    const now = Date.now()
    await ctx.db.patch(templateId, {
      kind: normalizedKind,
      title: normalizedTitle,
      body: sanitizedBody,
      updatedBy: actorId,
      updatedAt: now,
    })
  },
})

export const remove = mutation({
  args: {
    templateId: v.id("commentTemplates"),
    tenantId: v.string(),
    actorId: v.id("users"),
  },
  handler: async (ctx, { templateId, tenantId, actorId }) => {
    await requireStaff(ctx, actorId, tenantId)
    const template = await ctx.db.get(templateId)
    if (!template || template.tenantId !== tenantId) {
      throw new ConvexError("Template não encontrado")
    }
    await ctx.db.delete(templateId)
  },
})
