import { randomBytes } from "node:crypto";

import { env } from "../config.js";
import { AppError } from "../lib/errors.js";
import { supabaseAdmin } from "../lib/supabase.js";
import { isoNow } from "../lib/utils.js";
import { logCampaignActivity, logContactActivity } from "./activity-log-service.js";

const publicApiBaseUrl = (env.API_PUBLIC_BASE_URL || env.APP_BASE_URL).replace(/\/$/, "");

type SuppressionStatus = "unsubscribed" | "bounced" | "complained";

type ApplyContactSuppressionInput = {
  organizationId: string;
  contactId: string;
  status: SuppressionStatus;
  source: string;
  reason?: string | null;
  campaignId?: string | null;
  campaignSendId?: string | null;
  actorAuthUserId?: string | null;
  requestMetadata?: Record<string, unknown>;
};

type UnsubscribeTokenUseInput = {
  token: string;
  usedVia: string;
  requestMetadata?: Record<string, unknown>;
};

function nowAndPatch() {
  const now = isoNow();
  return {
    now,
    patch: {
      updated_at: now,
      last_activity_at: now,
    } as Record<string, unknown>,
  };
}

export function buildUnsubscribeUrl(token: string) {
  return `${publicApiBaseUrl}/api/public/unsubscribe/${encodeURIComponent(token)}`;
}

export function buildListUnsubscribeHeaders(url: string) {
  return {
    "List-Unsubscribe": `<${url}>`,
    "List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
  };
}

export function appendUnsubscribeFooter(html: string, text: string, unsubscribeUrl: string) {
  const htmlFooter = `
<section style="padding:20px 24px 28px;border-top:1px solid #e5e7eb;background:#fafaf9;text-align:center;font-family:Arial,sans-serif;">
  <p style="margin:0;font-size:12px;line-height:1.7;color:#64748b;">
    Do not want these updates anymore?
    <a href="${unsubscribeUrl}" style="color:#ea580c;font-weight:600;text-decoration:underline;">Unsubscribe instantly</a>.
  </p>
</section>`;
  const textFooter = `\n\n---\nUnsubscribe instantly: ${unsubscribeUrl}\n`;

  const withHtmlFooter = /<\/body>/i.test(html)
    ? html.replace(/<\/body>/i, `${htmlFooter}</body>`)
    : `${html}${htmlFooter}`;

  return {
    html: withHtmlFooter,
    text: `${text.trimEnd()}${textFooter}`,
  };
}

export async function createContactUnsubscribeToken(input: {
  organizationId: string;
  contactId: string;
  campaignId?: string | null;
  campaignSendId?: string | null;
  recipientEmail?: string | null;
}) {
  const token = randomBytes(24).toString("hex");
  const { error } = await supabaseAdmin
    .from("contact_unsubscribe_tokens")
    .insert({
      organization_id: input.organizationId,
      contact_id: input.contactId,
      campaign_id: input.campaignId ?? null,
      campaign_send_id: input.campaignSendId ?? null,
      token,
      recipient_email: input.recipientEmail ?? null,
      created_at: isoNow(),
    });

  if (error) {
    throw new AppError(400, "UNSUBSCRIBE_TOKEN_CREATE_FAILED", error.message);
  }

  return {
    token,
    unsubscribeUrl: buildUnsubscribeUrl(token),
  };
}

export async function applyContactSuppressionStatus(input: ApplyContactSuppressionInput) {
  const { data: contact, error } = await supabaseAdmin
    .from("contacts")
    .select("id, organization_id, email, status, unsubscribed_at, unsubscribed_via, bounced_at, complained_at")
    .eq("id", input.contactId)
    .eq("organization_id", input.organizationId)
    .maybeSingle();

  if (error) {
    throw new AppError(400, "CONTACT_STATUS_LOOKUP_FAILED", error.message);
  }

  if (!contact) {
    return null;
  }

  const currentStatus = String(contact.status ?? "subscribed");
  const { now, patch } = nowAndPatch();
  let nextStatus = currentStatus;
  let changed = false;

  if (input.status === "unsubscribed") {
    nextStatus = "unsubscribed";
    if (currentStatus !== "unsubscribed") {
      patch.status = nextStatus;
      patch.last_status_changed_at = now;
      patch.status_source = input.source;
      patch.status_reason = input.reason ?? "contact_unsubscribed";
      changed = true;
    }
    if (!contact.unsubscribed_at) {
      patch.unsubscribed_at = now;
      changed = true;
    }
    if (!contact.unsubscribed_via) {
      patch.unsubscribed_via = input.source;
      changed = true;
    }
    if (input.campaignId) patch.unsubscribed_campaign_id = input.campaignId;
    if (input.campaignSendId) patch.unsubscribed_campaign_send_id = input.campaignSendId;
  }

  if (input.status === "complained") {
    if (!contact.complained_at) {
      patch.complained_at = now;
      changed = true;
    }
    if (currentStatus !== "unsubscribed" && currentStatus !== "complained") {
      patch.status = "complained";
      patch.last_status_changed_at = now;
      patch.status_source = input.source;
      patch.status_reason = input.reason ?? "provider_complaint";
      nextStatus = "complained";
      changed = true;
    }
  }

  if (input.status === "bounced") {
    if (!contact.bounced_at) {
      patch.bounced_at = now;
      changed = true;
    }
    if (currentStatus === "subscribed") {
      patch.status = "bounced";
      patch.last_status_changed_at = now;
      patch.status_source = input.source;
      patch.status_reason = input.reason ?? "provider_bounce";
      nextStatus = "bounced";
      changed = true;
    }
  }

  if (!changed) {
    return contact;
  }

  const { data: updatedContact, error: updateError } = await supabaseAdmin
    .from("contacts")
    .update(patch)
    .eq("id", input.contactId)
    .eq("organization_id", input.organizationId)
    .select("id, organization_id, email, status, unsubscribed_at, unsubscribed_via, bounced_at, complained_at")
    .single();

  if (updateError || !updatedContact) {
    throw new AppError(400, "CONTACT_STATUS_UPDATE_FAILED", updateError?.message ?? "Unable to update contact status.");
  }

  await logContactActivity({
    organizationId: input.organizationId,
    contactId: input.contactId,
    actorAuthUserId: input.actorAuthUserId ?? null,
    action: input.status === "unsubscribed" ? "contact.unsubscribed" : input.status === "complained" ? "contact.complained" : "contact.bounced",
    metadata: {
      status: updatedContact.status,
      source: input.source,
      reason: input.reason ?? null,
      campaignId: input.campaignId ?? null,
      campaignSendId: input.campaignSendId ?? null,
      requestMetadata: input.requestMetadata ?? {},
    }
  });

  if (input.campaignId) {
    await logCampaignActivity({
      organizationId: input.organizationId,
      campaignId: input.campaignId,
      campaignSendId: input.campaignSendId ?? null,
      actorAuthUserId: input.actorAuthUserId ?? null,
      action: input.status === "unsubscribed" ? "campaign.recipient_unsubscribed" : input.status === "complained" ? "campaign.recipient_complained" : "campaign.recipient_bounced",
      metadata: {
        contactId: input.contactId,
        recipient: updatedContact.email,
        source: input.source,
        reason: input.reason ?? null,
      }
    });
  }

  return updatedContact;
}

export async function unsubscribeContactByToken(input: UnsubscribeTokenUseInput) {
  const { data: tokenRow, error } = await supabaseAdmin
    .from("contact_unsubscribe_tokens")
    .select("id, organization_id, contact_id, campaign_id, campaign_send_id, recipient_email, used_at")
    .eq("token", input.token)
    .maybeSingle();

  if (error) {
    throw new AppError(400, "UNSUBSCRIBE_LOOKUP_FAILED", error.message);
  }

  if (!tokenRow) {
    throw new AppError(404, "UNSUBSCRIBE_NOT_FOUND", "This unsubscribe link is invalid or has expired.");
  }

  if (!tokenRow.used_at) {
    const { error: tokenUpdateError } = await supabaseAdmin
      .from("contact_unsubscribe_tokens")
      .update({
        used_at: isoNow(),
        used_via: input.usedVia,
        request_metadata: input.requestMetadata ?? {},
      })
      .eq("id", tokenRow.id);

    if (tokenUpdateError) {
      throw new AppError(400, "UNSUBSCRIBE_UPDATE_FAILED", tokenUpdateError.message);
    }
  }

  const contact = await applyContactSuppressionStatus({
    organizationId: String(tokenRow.organization_id),
    contactId: String(tokenRow.contact_id),
    status: "unsubscribed",
    source: input.usedVia,
    reason: "one_click_unsubscribe",
    campaignId: tokenRow.campaign_id ? String(tokenRow.campaign_id) : null,
    campaignSendId: tokenRow.campaign_send_id ? String(tokenRow.campaign_send_id) : null,
    requestMetadata: input.requestMetadata,
  });

  return {
    contact,
    tokenRow,
  };
}
