import { randomUUID } from "node:crypto";
import { normalizeText } from "./utils.js";

const DEFAULT_SUBJECT = "Quick question about {{business}}";
const DEFAULT_BODY = `Hi {{name}},

I found {{business}} while researching {{niche}} in {{location}}.

Would you be open to a quick conversation this week?

Reply here or unsubscribe: {{unsubscribe_url}}`;

export class EmailCampaignService {
  constructor({ storage, publicBaseUrl = "" } = {}) {
    this.storage = storage;
    this.publicBaseUrl = publicBaseUrl.replace(/\/$/, "");
  }

  status() {
    return {
      backend: process.env.LISTMONK_URL ? "listmonk" : "local-draft",
      listmonkConfigured: Boolean(process.env.LISTMONK_URL && (process.env.LISTMONK_API_TOKEN || process.env.LISTMONK_PASSWORD)),
      compliance: {
        unsubscribe: true,
        suppressionList: true,
        bounceWebhook: true,
        clickWebhook: true,
        openWebhook: true
      },
      sending: {
        enabled: process.env.HERMES_EMAIL_SEND_ENABLED === "1",
        dailyLimit: Number(process.env.HERMES_EMAIL_DAILY_LIMIT || 100),
        perMinuteLimit: Number(process.env.HERMES_EMAIL_PER_MINUTE_LIMIT || 10)
      }
    };
  }

  async createDraft(run, input = {}) {
    if (!run) {
      const error = new Error("Run not found.");
      error.statusCode = 404;
      throw error;
    }
    const suppression = await this.storage.getSuppressionList();
    const recipients = campaignRecipients(run).filter((recipient) => !suppression.has(recipient.email.toLowerCase()));
    const campaign = {
      id: randomUUID(),
      runId: run.id,
      status: "draft",
      backend: this.status().backend,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      name: normalizeText(input.name || `${run.input?.niche || "Lead"} outreach`),
      subject: normalizeText(input.subject || DEFAULT_SUBJECT),
      body: String(input.body || DEFAULT_BODY),
      fromEmail: normalizeText(input.fromEmail || process.env.HERMES_EMAIL_FROM || ""),
      replyTo: normalizeText(input.replyTo || process.env.HERMES_EMAIL_REPLY_TO || process.env.HERMES_EMAIL_FROM || ""),
      niche: run.input?.niche || "",
      location: run.input?.locationScope || run.input?.cities?.[0] || run.input?.countryScope || "",
      recipients,
      suppressionSkipped: campaignRecipients(run).length - recipients.length,
      compliance: this.complianceBlock(),
      tracking: {
        sent: 0,
        opened: 0,
        clicked: 0,
        replied: 0,
        bounced: 0,
        unsubscribed: 0
      },
      events: []
    };
    await this.storage.saveCampaign(campaign);
    return campaign;
  }

  async listCampaigns() {
    return this.storage.listCampaigns();
  }

  async getCampaign(id) {
    return this.storage.getCampaign(id);
  }

  async sendCampaign(id) {
    const campaign = await this.storage.getCampaign(id);
    if (!campaign) return null;
    if (process.env.HERMES_EMAIL_SEND_ENABLED !== "1") {
      campaign.status = "ready";
      campaign.updatedAt = new Date().toISOString();
      campaign.events.unshift({
        at: campaign.updatedAt,
        type: "send_blocked",
        message: "Sending is disabled. Set HERMES_EMAIL_SEND_ENABLED=1 after Listmonk is configured."
      });
      await this.storage.saveCampaign(campaign);
      return campaign;
    }
    if (!this.status().listmonkConfigured) {
      const error = new Error("Listmonk is not configured. Set LISTMONK_URL plus LISTMONK_API_TOKEN or LISTMONK_USERNAME/LISTMONK_PASSWORD.");
      error.statusCode = 409;
      throw error;
    }

    const listmonk = await this.createListmonkCampaign(campaign);
    campaign.status = "sent";
    campaign.backend = "listmonk";
    campaign.listmonk = listmonk;
    campaign.tracking.sent = campaign.recipients.length;
    campaign.updatedAt = new Date().toISOString();
    campaign.events.unshift({
      at: campaign.updatedAt,
      type: "sent",
      message: `Handed ${campaign.recipients.length} recipients to Listmonk campaign ${listmonk?.id || ""}.`
    });
    await this.storage.saveCampaign(campaign);
    return campaign;
  }

  async recordEvent(id, event = {}) {
    const campaign = await this.storage.getCampaign(id);
    if (!campaign) return null;
    const type = normalizeText(event.type || "");
    if (!type) return campaign;
    campaign.events ||= [];
    campaign.events.unshift({
      at: new Date().toISOString(),
      type,
      email: normalizeText(event.email || ""),
      message: normalizeText(event.message || "")
    });
    campaign.events = campaign.events.slice(0, 1000);
    if (type in campaign.tracking) campaign.tracking[type] += 1;
    if (type === "bounce" || type === "bounced") campaign.tracking.bounced += 1;
    if (type === "unsubscribe" || type === "unsubscribed") {
      campaign.tracking.unsubscribed += 1;
      if (event.email) await this.storage.addSuppression(event.email, { campaignId: id, reason: "unsubscribe" });
    }
    campaign.updatedAt = new Date().toISOString();
    await this.storage.saveCampaign(campaign);
    return campaign;
  }

  async unsubscribe(email, reason = "manual") {
    return this.storage.addSuppression(email, { reason });
  }

  complianceBlock() {
    return {
      unsubscribeRequired: true,
      unsubscribeUrlTemplate: this.publicBaseUrl ? `${this.publicBaseUrl}/api/unsubscribe?email={{email}}` : "/api/unsubscribe?email={{email}}",
      suppressionList: "data/suppression/emails.json",
      bounceHandling: "POST /api/campaigns/:id/events with type=bounced",
      trackingHandling: "POST /api/campaigns/:id/events with type=opened/clicked/replied"
    };
  }

  async createListmonkCampaign(campaign) {
    const baseUrl = process.env.LISTMONK_URL.replace(/\/$/, "");
    const auth = process.env.LISTMONK_API_TOKEN
      ? `token ${process.env.LISTMONK_API_TOKEN}`
      : `Basic ${Buffer.from(`${process.env.LISTMONK_USERNAME || "admin"}:${process.env.LISTMONK_PASSWORD || ""}`).toString("base64")}`;
    const response = await fetch(`${baseUrl}/api/campaigns`, {
      method: "POST",
      headers: {
        "authorization": auth,
        "content-type": "application/json"
      },
      body: JSON.stringify({
        name: campaign.name,
        subject: campaign.subject,
        type: "regular",
        content_type: "richtext",
        body: campaign.body,
        tags: ["hermes", campaign.niche].filter(Boolean)
      })
    });
    if (!response.ok) {
      const detail = await response.text().catch(() => "");
      const error = new Error(`Listmonk campaign create failed: ${response.status} ${detail.slice(0, 300)}`);
      error.statusCode = 502;
      throw error;
    }
    return response.json();
  }
}

function campaignRecipients(run = {}) {
  return (run.qualifiedLeads || [])
    .filter((lead) => !lead.excluded && lead.approved !== false)
    .map((lead) => {
      const email = lead.ownerEmail || lead.email || lead.businessEmail || "";
      return {
        leadId: lead.id || "",
        email: normalizeEmail(email),
        phone: lead.ownerPhone || lead.phone || lead.businessPhone || "",
        name: lead.ownerName || lead.name || "",
        business: lead.name || "",
        location: lead.city || "",
        website: lead.website || "",
        score: lead.quality?.score || 0
      };
    })
    .filter((recipient) => recipient.email);
}

function normalizeEmail(value = "") {
  const email = String(value || "").trim().toLowerCase();
  if (!/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/.test(email)) return "";
  if (/\.(png|jpe?g|gif|svg|webp|css|js|json|ico)$/i.test(email)) return "";
  return email;
}
