import { decryptSecret } from "@/lib/ai/crypto";
import { createAdminClient } from "@/lib/supabase/admin";
import { getIntegrationEventLabel } from "@/lib/integrations/catalog";
import type { WebhookEventEnvelope } from "@/lib/developers/webhooks";
import type { IntegrationConnection } from "@/types";

function timeoutSignal(timeoutMs: number) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  return {
    signal: controller.signal,
    clear() {
      clearTimeout(timer);
    },
  };
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function getPrimaryEntity(data: Record<string, unknown>) {
  const keys = ["project", "task", "note", "event"] as const;

  for (const key of keys) {
    const candidate = data[key];
    if (isRecord(candidate)) {
      return { kind: key, value: candidate };
    }
  }

  return null;
}

function getPrimaryTitle(data: Record<string, unknown>) {
  const entity = getPrimaryEntity(data);
  if (!entity) return null;

  const name = entity.value.name;
  if (typeof name === "string" && name.trim()) return name.trim();

  const title = entity.value.title;
  if (typeof title === "string" && title.trim()) return title.trim();

  return null;
}

function getChangeSummary(data: Record<string, unknown>) {
  const action = typeof data.action === "string" ? data.action.replaceAll("_", " ") : null;
  const previousTask = isRecord(data.previous_task) ? data.previous_task : null;
  const task = isRecord(data.task) ? data.task : null;
  const previousProject = isRecord(data.previous_project) ? data.previous_project : null;
  const project = isRecord(data.project) ? data.project : null;

  if (
    previousTask &&
    task &&
    typeof previousTask.status === "string" &&
    typeof task.status === "string" &&
    previousTask.status !== task.status
  ) {
    return `Status: \`${previousTask.status}\` -> \`${task.status}\``;
  }

  if (
    previousProject &&
    project &&
    typeof previousProject.approval_status === "string" &&
    typeof project.approval_status === "string" &&
    previousProject.approval_status !== project.approval_status
  ) {
    return `Approval: \`${previousProject.approval_status}\` -> \`${project.approval_status}\``;
  }

  return action ? `Action: ${action}` : null;
}

function buildSlackPayload(envelope: WebhookEventEnvelope) {
  const eventLabel = getIntegrationEventLabel(envelope.type);
  const title = getPrimaryTitle(envelope.data) || "Workspace update";
  const workspaceLabel = envelope.workspace.team_id ? "Team workspace" : "Personal workspace";
  const summary = getChangeSummary(envelope.data);

  return {
    text: `${eventLabel}: ${title}`,
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: eventLabel,
          emoji: true,
        },
      },
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: summary ? `*${title}*\n${summary}` : `*${title}*`,
        },
      },
      {
        type: "context",
        elements: [
          {
            type: "mrkdwn",
            text: `${workspaceLabel} • ${new Date(envelope.created_at).toLocaleString()}`,
          },
        ],
      },
    ],
  };
}

export async function deliverSlackIntegrationEvent(
  admin: ReturnType<typeof createAdminClient>,
  connection: IntegrationConnection & { secret_encrypted: string },
  envelope: WebhookEventEnvelope
) {
  const webhookUrl = decryptSecret(connection.secret_encrypted);
  const payload = buildSlackPayload(envelope);

  let responseStatus: number | null = null;
  let responseBody: string | null = null;
  let success = false;

  const { signal, clear } = timeoutSignal(8000);

  try {
    const response = await fetch(webhookUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "User-Agent": "Mindavio-Integrations/1.0",
      },
      body: JSON.stringify(payload),
      signal,
    });

    responseStatus = response.status;
    responseBody = (await response.text()).slice(0, 4000) || null;
    success = response.ok;
  } catch (error) {
    responseBody =
      error instanceof Error ? error.message.slice(0, 4000) : "Slack delivery failed";
  } finally {
    clear();
  }

  await admin.from("integration_deliveries").insert({
    connection_id: connection.id,
    user_id: connection.user_id,
    team_id: connection.team_id,
    provider: connection.provider,
    event_type: envelope.type,
    payload: envelope,
    response_status: responseStatus,
    response_body: responseBody,
    success,
  });

  await admin
    .from("integration_connections")
    .update({
      last_delivery_at: new Date().toISOString(),
      last_response_status: responseStatus,
      last_error: success ? null : responseBody,
    })
    .eq("id", connection.id);
}
