/**
 * Marketing compliance core — legal-grade hard floor.
 * The compliant path is the only path; adapters MUST route sends through here.
 */

import type { Campaign, ConsentRecord, SuppressionEntry } from './index.js'

export type ComplianceRegion = 'US' | 'EU' | 'IL' | (string & {})

export type SenderLegalDeclaration = {
  spf: boolean
  dkim: boolean
  dmarc: boolean
  physicalPostalAddress: string
  advertisingLabel: string
}

export type CampaignLegalContext = {
  region?: ComplianceRegion
  legal: SenderLegalDeclaration
  /** HTTPS one-click unsubscribe URL (RFC 8058). */
  oneClickUnsubscribeUrl: string
}

export type CompliantRecipientMessage = {
  email: string
  subject: string
  html: string
  text?: string
  headers: Record<string, string>
}

export type SendCampaignRefusal = {
  email: string
  code: string
  reason: string
}

export type CompliantSendResult = {
  sent: string[]
  refused: SendCampaignRefusal[]
}

/** Host-owned suppression + consent store (self-managed: authoritative; ESP: mirror for defense-in-depth). */
export interface ComplianceStore {
  isSuppressed(email: string): Promise<boolean>
  getConsent(email: string): Promise<ConsentRecord | null>
  setConsent(record: ConsentRecord): Promise<void>
  addSuppression(entry: SuppressionEntry): Promise<void>
  /** Full suppression list — backs the `syncSuppression` LCD verb; store MUST be enumerable. */
  listSuppressed(): Promise<SuppressionEntry[]>
}

export class ComplianceError extends Error {
  override readonly name = 'ComplianceError'

  constructor(
    message: string,
    readonly code: string,
  ) {
    super(message)
  }
}

const IL_PROMOTIONAL_LABEL = 'פרסומת'

const OPT_IN_REGIONS = new Set<ComplianceRegion>(['EU', 'IL'])

function normalizeEmail(email: string): string {
  return email.trim().toLowerCase()
}

function requiresDoubleOptIn(region?: ComplianceRegion): boolean {
  if (!region) return true
  return OPT_IN_REGIONS.has(region as ComplianceRegion)
}

/** Default-on IL/EU — records confirmed double-opt-in consent. */
export async function confirmDoubleOptIn(
  store: ComplianceStore,
  email: string,
  region?: ComplianceRegion,
  now: () => string = () => new Date().toISOString(),
): Promise<ConsentRecord> {
  const normalized = normalizeEmail(email)
  const existing = (await store.getConsent(normalized)) ?? {
    email: normalized,
    doubleOptInConfirmed: false,
    trackingConsent: false,
  }

  const record: ConsentRecord = {
    ...existing,
    email: normalized,
    doubleOptInConfirmed: true,
    confirmedAt: existing.confirmedAt ?? now(),
    region: region ?? existing.region,
  }

  await store.setConsent(record)
  return record
}

export async function recordTrackingConsent(
  store: ComplianceStore,
  email: string,
  now: () => string = () => new Date().toISOString(),
): Promise<ConsentRecord> {
  const normalized = normalizeEmail(email)
  const existing = (await store.getConsent(normalized)) ?? {
    email: normalized,
    doubleOptInConfirmed: false,
    trackingConsent: false,
  }

  const record: ConsentRecord = {
    ...existing,
    email: normalized,
    trackingConsent: true,
    trackingConsentAt: existing.trackingConsentAt ?? now(),
  }

  await store.setConsent(record)
  return record
}

/** Pre-send legal gate — blocks campaigns missing required sender declarations. */
export function validatePreSendLegalGate(ctx: CampaignLegalContext): void {
  const { legal, region } = ctx

  if (!legal.spf || !legal.dkim || !legal.dmarc) {
    throw new ComplianceError(
      'campaign blocked: SPF, DKIM, and DMARC must all be declared on the sending domain',
      'missing-domain-auth',
    )
  }

  if (!legal.physicalPostalAddress?.trim()) {
    throw new ComplianceError(
      'campaign blocked: physical postal address is required',
      'missing-postal-address',
    )
  }

  if (!legal.advertisingLabel?.trim()) {
    throw new ComplianceError(
      'campaign blocked: advertising label is required',
      'missing-advertising-label',
    )
  }

  if (region === 'IL' && !legal.advertisingLabel.includes(IL_PROMOTIONAL_LABEL)) {
    throw new ComplianceError(
      `campaign blocked: IL promotional mail requires the "${IL_PROMOTIONAL_LABEL}" advertising label`,
      'missing-il-promotional-label',
    )
  }
}

/** RFC 8058 one-click unsubscribe headers — injected on every compliant send. */
export function buildRfc8058Headers(oneClickUnsubscribeUrl: string): Record<string, string> {
  const url = oneClickUnsubscribeUrl.trim()
  if (!url) {
    throw new ComplianceError('one-click unsubscribe URL is required', 'missing-unsubscribe-url')
  }
  return {
    'List-Unsubscribe': `<${url}>`,
    'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
  }
}

export type TrackingOpts = {
  campaignId: string
  email: string
  trackingBaseUrl: string
  hasTrackingConsent: boolean
}

/** Tracking pixel + click redirect emitted ONLY when per-contact tracking consent is recorded. */
export function applyTracking(html: string, opts: TrackingOpts): string {
  if (!opts.hasTrackingConsent) {
    return stripTrackingArtifacts(html)
  }

  const pixelUrl = `${opts.trackingBaseUrl.replace(/\/$/, '')}/o/${encodeURIComponent(opts.campaignId)}/${encodeURIComponent(opts.email)}`
  const pixel = `<img src="${pixelUrl}" width="1" height="1" alt="" />`
  const withPixel = html.includes('</body>')
    ? html.replace('</body>', `${pixel}</body>`)
    : `${html}${pixel}`

  return withPixel.replace(
    /href="(https?:\/\/[^"]+)"/gi,
    (_match, url: string) =>
      `href="${opts.trackingBaseUrl.replace(/\/$/, '')}/c/${encodeURIComponent(opts.campaignId)}/${encodeURIComponent(opts.email)}?u=${encodeURIComponent(url)}"`,
  )
}

function stripTrackingArtifacts(html: string): string {
  return html
    .replace(/<img[^>]+src="[^"]*\/o\/[^"]*"[^>]*>/gi, '')
    .replace(/href="[^"]*\/c\/[^"]*\?u=([^"]+)"/gi, 'href="$1"')
}

export function assertRecipientEligible(
  email: string,
  consent: ConsentRecord | null,
  suppressed: boolean,
  region?: ComplianceRegion,
): SendCampaignRefusal | null {
  const normalized = normalizeEmail(email)

  if (suppressed) {
    return {
      email: normalized,
      code: 'suppressed',
      reason: 'recipient is on the suppression list',
    }
  }

  if (requiresDoubleOptIn(region) && !consent?.doubleOptInConfirmed) {
    return {
      email: normalized,
      code: 'unconfirmed-consent',
      reason: 'double opt-in is not confirmed for this recipient',
    }
  }

  return null
}

export type CompliantSendInput = {
  campaignId: string
  campaign: Campaign
  legal: CampaignLegalContext
  recipients: string[]
  trackingBaseUrl: string
}

/**
 * Compliance-wrapped per-recipient send — suppression + consent gate, legal pre-check,
 * tracking-off-by-default, RFC 8058 header injection.
 */
export async function executeCompliantSend(
  store: ComplianceStore,
  input: CompliantSendInput,
  sendOne: (message: CompliantRecipientMessage) => Promise<void>,
): Promise<CompliantSendResult> {
  validatePreSendLegalGate(input.legal)

  const sent: string[] = []
  const refused: SendCampaignRefusal[] = []
  const rfc8058 = buildRfc8058Headers(input.legal.oneClickUnsubscribeUrl)

  for (const rawEmail of input.recipients) {
    const email = normalizeEmail(rawEmail)
    const suppressed = await store.isSuppressed(email)
    const consent = await store.getConsent(email)
    const refusal = assertRecipientEligible(
      email,
      consent,
      suppressed,
      input.legal.region ?? input.campaign.region,
    )

    if (refusal) {
      refused.push(refusal)
      continue
    }

    const html = applyTracking(input.campaign.html, {
      campaignId: input.campaignId,
      email,
      trackingBaseUrl: input.trackingBaseUrl,
      hasTrackingConsent: consent?.trackingConsent === true,
    })

    await sendOne({
      email,
      subject: input.campaign.subject,
      html,
      text: input.campaign.text,
      headers: { ...rfc8058 },
    })
    sent.push(email)
  }

  return { sent, refused }
}

/** In-memory ComplianceStore for tests and self-managed hosts without a wired DB yet. */
export function createMemoryComplianceStore(
  initial?: {
    suppressed?: SuppressionEntry[]
    consents?: ConsentRecord[]
  },
): ComplianceStore & {
  suppressed: SuppressionEntry[]
  consents: Map<string, ConsentRecord>
} {
  const suppressed = [...(initial?.suppressed ?? [])]
  const consents = new Map<string, ConsentRecord>()
  for (const record of initial?.consents ?? []) {
    consents.set(normalizeEmail(record.email), {
      ...record,
      email: normalizeEmail(record.email),
    })
  }

  return {
    suppressed,
    consents,
    async isSuppressed(email: string) {
      const normalized = normalizeEmail(email)
      return suppressed.some((entry) => normalizeEmail(entry.email) === normalized)
    },
    async listSuppressed() {
      return [...suppressed]
    },
    async getConsent(email: string) {
      return consents.get(normalizeEmail(email)) ?? null
    },
    async setConsent(record: ConsentRecord) {
      consents.set(normalizeEmail(record.email), {
        ...record,
        email: normalizeEmail(record.email),
      })
    },
    async addSuppression(entry: SuppressionEntry) {
      const normalized = normalizeEmail(entry.email)
      if (!suppressed.some((e) => normalizeEmail(e.email) === normalized)) {
        suppressed.push({ ...entry, email: normalized })
      }
    },
  }
}
