/**
 * Mailchimp Adapter
 *
 * Implements ProviderAdapter for Mailchimp.
 * Wraps the existing MailchimpProvider (EmailProviderService) and adds:
 *   - Automatic list ID resolution when not provided
 *   - Retry with exponential backoff
 *   - Error normalization
 *
 * Auth: API key with server prefix (key-dc format)
 *
 * Note: Mailchimp's automation API is limited. triggerAutomation works by
 * subscribing a contact to a list that feeds a Classic Automation.
 */

import type { EmailProviderService, ContactData, SendCampaignOptions } from '../../email/EmailProviderService';
import type {
  ProviderAdapter,
  AddContactInput,
  SendCampaignInput,
  TriggerAutomationInput,
  ProviderResult,
  AddContactOutput,
  SendCampaignOutput,
  TriggerAutomationOutput,
  GetStatusOutput,
} from './types';
import { normalizeProviderError } from './errorNormalizer';
import { withRetry } from './retry';

export class MailchimpAdapter implements ProviderAdapter {
  private provider: EmailProviderService;

  constructor(provider: EmailProviderService) {
    this.provider = provider;
  }

  // ===========================================
  // ADD CONTACT
  // ===========================================

  async addContact(input: AddContactInput): Promise<ProviderResult<AddContactOutput>> {
    try {
      // Mailchimp requires a list ID for contact creation.
      // If provided, use it. Otherwise, fetch the first available list.
      let listId: string | number | undefined = input.listIds?.[0];

      if (!listId) {
        // Fetch first available list
        const lists = await withRetry(
          () => this.provider.getLists(1, 0),
          'addContact.getLists',
          'mailchimp'
        );

        if (!lists || lists.length === 0) {
          return {
            success: false,
            error: {
              provider: 'mailchimp',
              code: 'LIST_NOT_FOUND' as const,
              message: 'No Mailchimp audience/list available. Create an audience first.',
              retryable: false,
            } as any,
          };
        }

        listId = lists[0].id;
      }

      // Build attributes (Mailchimp calls them merge_fields)
      const attributes: Record<string, string> = {};
      if (input.firstName) attributes.FNAME = input.firstName;
      if (input.lastName) attributes.LNAME = input.lastName;
      if (input.phone) attributes.PHONE = input.phone;
      if (input.company) attributes.COMPANY = input.company;

      // Merge any additional attributes
      if (input.attributes) {
        Object.assign(attributes, input.attributes);
      }

      // Use addContactToListWithData for richer attribute support
      if (input.firstName || input.lastName || input.phone || input.company) {
        await withRetry(
          () => (this.provider as any).addContactToListWithData(listId, {
            email: input.email,
            firstName: input.firstName,
            lastName: input.lastName,
            phone: input.phone,
            company: input.company,
            ...(input.attributes ? { mergeFields: input.attributes } : {}),
          }),
          'addContact.addToListWithData',
          'mailchimp'
        );

        return {
          success: true,
          data: {
            contactId: 0,
            email: input.email,
            created: true,
          },
        };
      }

      // Simple contact creation
      const numericListIds = typeof listId === 'string' ? [parseInt(listId, 10)].filter(n => !isNaN(n)) : [listId];
      const contactData: ContactData = {
        email: input.email,
        attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
        listIds: numericListIds as number[],
        updateEnabled: true,
      };

      const result = await withRetry(
        () => this.provider.createContact(contactData),
        'addContact',
        'mailchimp'
      );

      return {
        success: true,
        data: {
          contactId: result.id,
          email: result.email || input.email,
          created: result.created ?? true,
        },
      };
    } catch (error) {
      const providerError = normalizeProviderError(error, 'mailchimp');

      // Mailchimp returns specific errors for already-subscribed members
      if (providerError.code === 'VALIDATION_ERROR' &&
          (providerError.message.toLowerCase().includes('already subscribed') ||
           providerError.message.toLowerCase().includes('member exists'))) {
        return {
          success: false,
          error: {
            provider: 'mailchimp',
            code: 'DUPLICATE_CONTACT' as const,
            message: `Contact ${input.email} already exists`,
            retryable: false,
          } as any,
        };
      }

      return { success: false, error: providerError };
    }
  }

  // ===========================================
  // SEND CAMPAIGN
  // ===========================================

  async sendCampaign(input: SendCampaignInput): Promise<ProviderResult<SendCampaignOutput>> {
    try {
      // Mailchimp requires a list ID for campaigns
      let listId: string | number | undefined = input.listIds?.[0];

      if (!listId) {
        const lists = await withRetry(
          () => this.provider.getLists(1, 0),
          'sendCampaign.getLists',
          'mailchimp'
        );
        if (!lists || lists.length === 0) {
          return {
            success: false,
            error: {
              provider: 'mailchimp',
              code: 'LIST_NOT_FOUND' as const,
              message: 'No Mailchimp audience/list available for campaign.',
              retryable: false,
            } as any,
          };
        }
        listId = lists[0].id;
      }

      // Step 1: Create the campaign
      const campaignOptions: SendCampaignOptions = {
        name: input.name,
        subject: input.subject,
        sender: {
          email: input.sender.email,
          name: input.sender.name,
          ...(input.sender.id ? { id: input.sender.id } : {}),
        },
        recipients: {
          listIds: [typeof listId === 'string' ? parseInt(listId, 10) : listId].filter(n => !isNaN(n as number)) as number[],
        },
      };

      if (input.htmlContent) campaignOptions.htmlContent = input.htmlContent;
      if (input.replyTo) campaignOptions.replyTo = input.replyTo;
      if (input.tags && input.tags.length > 0) campaignOptions.tags = input.tags;

      const createResult = await withRetry(
        () => this.provider.createCampaign(campaignOptions),
        'sendCampaign.create',
        'mailchimp'
      );

      // Step 2: Send the campaign (Mailchimp's createCampaign also sets content if htmlContent provided)
      if (!input.scheduledAt) {
        await withRetry(
          () => this.provider.sendCampaign(createResult.campaignId),
          'sendCampaign.send',
          'mailchimp'
        );
      } else {
        await withRetry(
          () => this.provider.scheduleCampaign(createResult.campaignId, input.scheduledAt!),
          'sendCampaign.schedule',
          'mailchimp'
        );
      }

      return {
        success: true,
        data: {
          campaignId: createResult.campaignId,
          status: input.scheduledAt ? 'scheduled' : 'sent',
        },
      };
    } catch (error) {
      return { success: false, error: normalizeProviderError(error, 'mailchimp') };
    }
  }

  // ===========================================
  // TRIGGER AUTOMATION
  // ===========================================

  async triggerAutomation(input: TriggerAutomationInput): Promise<ProviderResult<TriggerAutomationOutput>> {
    try {
      // Mailchimp's Classic Automations work by subscribing a contact to a list
      // that feeds the automation. The existing addContactToAutomation method
      // does this — if listIds are provided, it subscribes the contact to that list.

      const workflowId = parseInt(input.identifier, 10);
      if (isNaN(workflowId)) {
        return {
          success: false,
          error: {
            provider: 'mailchimp',
            code: 'VALIDATION_ERROR' as const,
            message: `Invalid Mailchimp automation ID: "${input.identifier}". Must be a numeric ID.`,
            retryable: false,
          } as any,
        };
      }

      const listIds = input.listIds?.map(id => typeof id === 'string' ? parseInt(id, 10) : id).filter(n => !isNaN(n));

      const result = await withRetry(
        () => this.provider.addContactToAutomation(workflowId, input.email, input.attributes, listIds),
        'triggerAutomation',
        'mailchimp'
      );

      return {
        success: result.success,
        data: {
          triggered: result.success,
          message: result.message || `Contact ${input.email} added to Mailchimp automation ${input.identifier}`,
        },
      };
    } catch (error) {
      return { success: false, error: normalizeProviderError(error, 'mailchimp') };
    }
  }

  // ===========================================
  // GET STATUS
  // ===========================================

  async getStatus(): Promise<ProviderResult<GetStatusOutput>> {
    try {
      // Try to get account info first
      const accountInfo = await this.provider.getAccountInfo();

      return {
        success: true,
        data: {
          connected: true,
          provider: 'mailchimp',
          accountEmail: accountInfo.email,
          accountName: accountInfo.firstName || undefined,
          plan: accountInfo.plan,
          credits: accountInfo.credits,
        },
      };
    } catch (error) {
      // Fall back to health check
      try {
        const health = await this.provider.healthCheck();
        return {
          success: true,
          data: {
            connected: health.status === 'ok',
            provider: 'mailchimp',
          },
        };
      } catch (healthError) {
        return { success: false, error: normalizeProviderError(error, 'mailchimp') };
      }
    }
  }
}