import { createMail, type MailMessage } from '@platform-modules/mail'
import {
  MarketingProviderError,
  registerMarketingAdapter,
  sendCampaignThroughCompliance,
  type Campaign,
  type CampaignStats,
  type ComplianceStore,
  type MarketingAdapter,
  type MarketingContact,
  type MarketingList,
  type SendCampaignOpts,
  type SendCampaignResult,
  type SuppressionEntry,
} from './index.js'

export type SelfManagedMail = {
  send(msg: MailMessage): Promise<{ id: string; provider: string }>
}

export type SelfManagedStore = {
  upsertContact(contact: MarketingContact, listId?: string): Promise<void>
  removeContact(email: string, listId?: string): Promise<void>
  tagContact(email: string, tag: string): Promise<void>
  createList(name: string): Promise<MarketingList>
  lists(): Promise<MarketingList[]>
  saveCampaign(campaign: Campaign): Promise<void>
  getCampaign(id: string): Promise<Campaign | null>
  getListRecipients(listIds: string[]): Promise<string[]>
  recordOpen(campaignId: string, email: string): Promise<void>
  recordClick(campaignId: string, email: string, url: string): Promise<void>
  getStats(campaignId: string): Promise<CampaignStats>
  createSegment(def: { name: string; listId: string; filter: SegmentFilter }): Promise<Segment>
  listSegments(listId?: string): Promise<Segment[]>
  scheduleCampaign(campaignId: string, scheduledAt: string): Promise<void>
}

export type SegmentFilter = {
  tag?: string
  attributeKey?: string
  attributeValue?: string
}

export type Segment = {
  id: string
  name: string
  listId: string
  filter: SegmentFilter
}

export type SelfManagedCreds = {
  from: string
  mail: SelfManagedMail
  store: SelfManagedStore
  complianceStore: ComplianceStore
  replyTo?: string
}

function campaignSendKey(campaignId: string, email: string): string {
  return `marketing:${encodeURIComponent(campaignId)}:${encodeURIComponent(email)}`
}

export function makeSelfManagedAdapter(creds: SelfManagedCreds): MarketingAdapter & {
  createSegment: SelfManagedStore['createSegment']
  listSegments: SelfManagedStore['listSegments']
  scheduleCampaign: SelfManagedStore['scheduleCampaign']
  recordOpen: SelfManagedStore['recordOpen']
  recordClick: SelfManagedStore['recordClick']
} {
  const { from, mail, store, complianceStore, replyTo } = creds
  const sender = createMail({ send: (msg) => mail.send(msg) })

  const adapter = {
    name: 'self-managed',
    supports: {
      segments: true,
      scheduling: true,
      automation: false,
    } as const,

    async upsertContact(contact: MarketingContact, listId?: string): Promise<void> {
      await store.upsertContact(contact, listId)
    },

    async removeContact(email: string, listId?: string): Promise<void> {
      await store.removeContact(email, listId)
    },

    async tagContact(email: string, tag: string): Promise<void> {
      await store.tagContact(email, tag)
    },

    async createList(name: string): Promise<MarketingList> {
      return store.createList(name)
    },

    async lists(): Promise<MarketingList[]> {
      return store.lists()
    },

    async createCampaign(campaign: Omit<Campaign, 'id'>): Promise<Campaign> {
      const created: Campaign = {
        ...campaign,
        id: `camp_${campaign.name.toLowerCase().replace(/\s+/g, '-')}`,
      }
      await store.saveCampaign(created)
      return created
    },

    async sendCampaign(campaignId: string, opts: SendCampaignOpts): Promise<SendCampaignResult> {
      const campaign = await store.getCampaign(campaignId)
      if (!campaign) {
        throw new MarketingProviderError(
          `campaign not found: ${campaignId}`,
          'self-managed',
          false,
        )
      }

      const recipients = await store.getListRecipients(campaign.listIds)

      return sendCampaignThroughCompliance(
        complianceStore,
        {
          campaignId,
          campaign,
          legal: opts.legal,
          recipients,
          trackingBaseUrl: opts.trackingBaseUrl,
        },
        async (message) => {
          await sender.send({
            from,
            to: message.email,
            replyTo,
            subject: message.subject,
            html: message.html,
            text: message.text,
            headers: message.headers,
            idempotencyKey: campaignSendKey(campaignId, message.email),
          })
        },
      )
    },

    async campaignStats(campaignId: string): Promise<CampaignStats> {
      return store.getStats(campaignId)
    },

    async syncSuppression(): Promise<SuppressionEntry[]> {
      return complianceStore.listSuppressed()
    },

    createSegment: store.createSegment.bind(store),
    listSegments: store.listSegments.bind(store),
    scheduleCampaign: store.scheduleCampaign.bind(store),
    recordOpen: store.recordOpen.bind(store),
    recordClick: store.recordClick.bind(store),
  }

  return adapter
}

registerMarketingAdapter('self-managed', (creds) => makeSelfManagedAdapter(creds as SelfManagedCreds))
