/**
 * Zoho Campaigns Provider Implementation
 *
 * Implements EmailProviderService using Zoho Campaigns REST API v1.1.
 * Uses OAuth 2.0 for authentication with multi-data-center support.
 *
 * Documentation: https://www.zoho.com/campaigns/help/developers/
 */

import axios, { AxiosInstance, AxiosError } from 'axios';
import type {
  EmailProviderService,
  SendCampaignOptions,
  CampaignResult,
  ContactData,
  ContactResult,
  ListData,
  ListResult,
  SenderData,
  SenderResult,
  CampaignStats,
  WebhookData,
  WebhookResult,
  AccountInfo,
  TemplateResult,
  AutomationWorkflow,
  AutomationContactResult,
} from './EmailProviderService';

// Zoho Data Centers configuration
const ZOHO_DATA_CENTERS: Record<string, { accounts: string; api: string }> = {
  com: { accounts: 'https://accounts.zoho.com', api: 'https://campaigns.zoho.com' },
  eu: { accounts: 'https://accounts.zoho.eu', api: 'https://campaigns.zoho.eu' },
  in: { accounts: 'https://accounts.zoho.in', api: 'https://campaigns.zoho.in' },
  au: { accounts: 'https://accounts.zoho.com.au', api: 'https://campaigns.zoho.com.au' },
  jp: { accounts: 'https://accounts.zoho.jp', api: 'https://campaigns.zoho.jp' },
  cn: { accounts: 'https://accounts.zoho.com.cn', api: 'https://campaigns.zoho.com.cn' },
  ca: { accounts: 'https://accounts.zohocloud.ca', api: 'https://campaigns.zohocloud.ca' },
};

// Default data center (US)
const DEFAULT_DATA_CENTER = 'com';

/**
 * Zoho Campaigns OAuth configuration
 */
export interface ZohoOAuthConfig {
  clientId: string;
  clientSecret: string;
  redirectUri: string;
  scope?: string;
}

/**
 * Zoho token response
 */
interface ZohoTokenResponse {
  access_token: string;
  refresh_token: string;
  api_domain: string;
  token_type: string;
  expires_in: number;
  location?: string;
  accounts_server?: string;
}

/**
 * Zoho API error response
 */
interface ZohoApiError {
  code: string;
  message: string;
  status: string;
}

/**
 * Rate limit configuration
 */
const RATE_LIMIT = {
  maxRequests: 500,
  windowMs: 5 * 60 * 1000, // 5 minutes
  retryAfter: 30 * 60 * 1000, // 30 minutes lock if exceeded
};

export class ZohoCampaignsProvider implements EmailProviderService {
  private accessToken: string;
  private refreshToken: string;
  private dataCenter: string;
  private apiDomain: string;
  private accountsServer: string;
  private clientId: string;
  private clientSecret: string;
  private tokenExpiresAt?: Date;
  private onTokenRefresh?: (accessToken: string, refreshToken: string, expiresAt: Date) => Promise<void>;

  private client: AxiosInstance;
  private requestCount: number = 0;
  private windowStartTime: number = Date.now();

  /**
   * Create a new Zoho Campaigns provider instance
   *
   * @param accessToken - Valid OAuth 2.0 access token
   * @param refreshToken - OAuth 2.0 refresh token
   * @param dataCenter - Data center code (com, eu, in, au, jp, cn, ca)
   * @param oauthConfig - OAuth credentials for token refresh
   * @param onTokenRefresh - Callback when tokens are refreshed
   */
  constructor(
    accessToken: string,
    refreshToken: string,
    dataCenter: string = DEFAULT_DATA_CENTER,
    oauthConfig?: { clientId: string; clientSecret: string },
    onTokenRefresh?: (accessToken: string, refreshToken: string, expiresAt: Date) => Promise<void>
  ) {
    this.accessToken = accessToken;
    this.refreshToken = refreshToken;
    this.dataCenter = dataCenter;
    this.onTokenRefresh = onTokenRefresh;

    const dcConfig = ZOHO_DATA_CENTERS[dataCenter] || ZOHO_DATA_CENTERS[DEFAULT_DATA_CENTER];
    this.apiDomain = dcConfig.api;
    this.accountsServer = dcConfig.accounts;

    if (oauthConfig) {
      this.clientId = oauthConfig.clientId;
      this.clientSecret = oauthConfig.clientSecret;
    }

    this.client = axios.create({
      baseURL: this.apiDomain,
      timeout: 30000,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    });

    // Add request interceptor for authentication
    this.client.interceptors.request.use(async (config) => {
      // Check if token needs refresh
      if (this.tokenExpiresAt && new Date() >= this.tokenExpiresAt) {
        await this.refreshAccessToken();
      }
      config.headers['Authorization'] = `Zoho-oauthtoken ${this.accessToken}`;
      return config;
    });

    // Add response interceptor for error handling
    this.client.interceptors.response.use(
      (response) => response,
      async (error: AxiosError) => {
        if (error.response?.status === 401) {
          // Token expired, try to refresh
          await this.refreshAccessToken();
          // Retry the request
          const config = error.config!;
          config.headers['Authorization'] = `Zoho-oauthtoken ${this.accessToken}`;
          return this.client.request(config);
        }
        throw error;
      }
    );
  }

  // ===========================================
  // OAUTH & TOKEN MANAGEMENT
  // ===========================================

  /**
   * Generate OAuth authorization URL
   */
  static getAuthorizationUrl(config: ZohoOAuthConfig, state: string, dataCenter: string = 'com'): string {
    const dcConfig = ZOHO_DATA_CENTERS[dataCenter] || ZOHO_DATA_CENTERS[DEFAULT_DATA_CENTER];
    const scope = config.scope || 'ZohoCampaigns.campaign.ALL,ZohoCampaigns.contact.ALL';

    const params = new URLSearchParams({
      response_type: 'code',
      client_id: config.clientId,
      scope: scope,
      redirect_uri: config.redirectUri,
      access_type: 'offline',
      prompt: 'consent',
      state: state,
    });

    return `${dcConfig.accounts}/oauth/v2/auth?${params.toString()}`;
  }

  /**
   * Exchange authorization code for tokens
   */
  static async exchangeCodeForTokens(
    code: string,
    config: ZohoOAuthConfig,
    dataCenter: string = 'com'
  ): Promise<{
    accessToken: string;
    refreshToken: string;
    apiDomain: string;
    accountsServer: string;
    expiresIn: number;
    location: string;
  }> {
    const dcConfig = ZOHO_DATA_CENTERS[dataCenter] || ZOHO_DATA_CENTERS[DEFAULT_DATA_CENTER];

    const params = new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: config.clientId,
      client_secret: config.clientSecret,
      redirect_uri: config.redirectUri,
      code: code,
    });

    const response = await axios.post<ZohoTokenResponse>(
      `${dcConfig.accounts}/oauth/v2/token`,
      params.toString(),
      {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      }
    );

    const data = response.data;

    return {
      accessToken: data.access_token,
      refreshToken: data.refresh_token,
      apiDomain: data.api_domain || dcConfig.api,
      accountsServer: data.accounts_server || dcConfig.accounts,
      expiresIn: data.expires_in,
      location: data.location || dataCenter,
    };
  }

  /**
   * Refresh the access token using refresh token
   */
  private async refreshAccessToken(): Promise<void> {
    if (!this.clientId || !this.clientSecret) {
      throw new Error('OAuth credentials not configured for token refresh');
    }

    const params = new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: this.clientId,
      client_secret: this.clientSecret,
      refresh_token: this.refreshToken,
    });

    const response = await axios.post<ZohoTokenResponse>(
      `${this.accountsServer}/oauth/v2/token`,
      params.toString(),
      {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      }
    );

    const data = response.data;
    this.accessToken = data.access_token;
    // Note: Zoho may return a new refresh token, but typically doesn't
    this.tokenExpiresAt = new Date(Date.now() + (data.expires_in * 1000));

    // Notify parent about token refresh
    if (this.onTokenRefresh && this.tokenExpiresAt) {
      await this.onTokenRefresh(this.accessToken, this.refreshToken, this.tokenExpiresAt);
    }
  }

  /**
   * Set token expiry time
   */
  setTokenExpiresAt(expiresAt: Date): void {
    this.tokenExpiresAt = expiresAt;
  }

  /**
   * Check rate limit before making request
   */
  private async checkRateLimit(): Promise<void> {
    const now = Date.now();
    const windowElapsed = now - this.windowStartTime;

    if (windowElapsed > RATE_LIMIT.windowMs) {
      // Reset window
      this.requestCount = 0;
      this.windowStartTime = now;
    }

    if (this.requestCount >= RATE_LIMIT.maxRequests) {
      // Wait until window resets
      const waitTime = RATE_LIMIT.windowMs - windowElapsed;
      throw new Error(`Rate limit exceeded. Retry after ${Math.ceil(waitTime / 1000)} seconds`);
    }

    this.requestCount++;
  }

  /**
   * Make API request with retry logic
   */
  private async makeRequest<T>(
    method: 'GET' | 'POST' | 'PUT' | 'DELETE',
    endpoint: string,
    params?: Record<string, any>,
    data?: Record<string, any>
  ): Promise<T> {
    await this.checkRateLimit();

    const config: any = {
      method,
      url: endpoint,
      params: { resfmt: 'JSON', ...params },
    };

    if (data) {
      config.data = new URLSearchParams(data).toString();
    }

    console.log('[ZohoCampaigns] Making request:', method, endpoint, 'params:', params);

    try {
      const response = await this.client.request<any>(config);
      console.log('[ZohoCampaigns] Response status:', response.status);
      console.log('[ZohoCampaigns] Response data keys:', Object.keys(response.data || {}));
      console.log('[ZohoCampaigns] Full response:', JSON.stringify(response.data).slice(0, 1000));
      return response.data as T;
    } catch (error: any) {
      console.error('[ZohoCampaigns] Request failed:', error.message);
      console.error('[ZohoCampaigns] Error response:', error.response?.data);
      const zohoError = error.response?.data as ZohoApiError;
      if (zohoError) {
        throw new Error(`Zoho API Error: ${zohoError.message} (Code: ${zohoError.code})`);
      }
      throw error;
    }
  }

  // ===========================================
  // CONNECTION & ACCOUNT
  // ===========================================

  async verifyConnection(): Promise<boolean> {
    try {
      await this.getAccountInfo();
      return true;
    } catch (error) {
      return false;
    }
  }

  async getAccountInfo(): Promise<AccountInfo> {
    // Zoho doesn't have a dedicated account endpoint like Brevo
    // We can get account info from getmailinglists or similar
    try {
      const response = await this.makeRequest<any>('GET', '/api/v1.1/getmailinglists', {
        range: 1,
      });

      // Return basic info - Zoho account details need to be fetched differently
      return {
        email: '',
        firstName: undefined,
        lastName: undefined,
        plan: undefined,
      };
    } catch (error) {
      throw error;
    }
  }

  // ===========================================
  // SENDERS
  // ===========================================

  async getSenders(): Promise<SenderResult[]> {
    // Zoho Campaigns doesn't have a separate sender management API like Brevo
    // Senders are managed through the Zoho Campaigns UI
    // We return empty array and rely on user-configured senders
    console.warn('[ZohoCampaigns] Sender management is done through Zoho Campaigns UI');
    return [];
  }

  async createSender(data: SenderData): Promise<SenderResult> {
    // Zoho Campaigns doesn't support sender creation via API
    throw new Error('Sender creation is not supported via Zoho Campaigns API. Please configure senders in Zoho Campaigns UI.');
  }

  // ===========================================
  // LISTS
  // ===========================================

  async getLists(limit: number = 50, offset: number = 0): Promise<ListResult[]> {
    console.log('[ZohoCampaigns] getLists called with limit:', limit, 'offset:', offset);
    console.log('[ZohoCampaigns] Data center:', this.dataCenter);
    console.log('[ZohoCampaigns] API domain:', this.apiDomain);

    // Zoho Campaigns API v1.1 endpoint: /api/v1.1/getmailinglists
    // resfmt=JSON is passed as query parameter
    const response = await this.makeRequest<any>('GET', '/api/v1.1/getmailinglists', {
      range: limit,
      fromindex: offset,
    });

    console.log('[ZohoCampaigns] Raw API response:', JSON.stringify(response, null, 2).slice(0, 2000));

    // Zoho API returns list_of_details array
    const lists = response.list_of_details || response.mailing_lists || response.response?.list_of_details || [];

    console.log('[ZohoCampaigns] Parsed lists count:', lists.length);
    if (lists.length > 0) {
      console.log('[ZohoCampaigns] First list sample:', JSON.stringify(lists[0]));
    }

    return lists.map((list: any) => ({
      id: list.listkey,
      name: list.listname || '',
      totalSubscribers: parseInt(list.noofcontacts || '0', 10),
      dynamicList: false,
    }));
  }

  async createList(data: ListData): Promise<ListResult> {
    console.log('[ZohoCampaigns] Creating list:', data.name);

    // Zoho Campaigns API v1.1 endpoint: /api/v1.1/addlistandcontacts
    const params: Record<string, any> = {
      listname: data.name,
      signupform: 'public',
      mode: 'newlist',
    };

    if (data.folderId) {
      params.folderid = data.folderId;
    }

    const response = await this.makeRequest<any>('POST', '/api/v1.1/addlistandcontacts', {}, params);

    console.log('[ZohoCampaigns] Create list response:', JSON.stringify(response).slice(0, 500));

    // Extract list key from response
    const listKey = response.listkey || response.response?.listkey;

    if (!listKey) {
      console.error('[ZohoCampaigns] No list key in response:', response);
      throw new Error('Failed to create list: No list key returned');
    }

    console.log('[ZohoCampaigns] List created successfully with key:', listKey);

    return {
      id: listKey,
      name: data.name,
      totalSubscribers: 0,
      dynamicList: false,
    };
  }

  async addContactsToList(listId: number | string, emails: string[]): Promise<void> {
    // Convert to string for Zoho API (listkey is a string)
    const listKey = String(listId);

    // Zoho limits to 10 emails per call for listsubscribe
    const maxPerCall = 10;

    for (let i = 0; i < emails.length; i += maxPerCall) {
      const batch = emails.slice(i, i + maxPerCall);

      await this.makeRequest<any>('POST', '/api/v1.1/listsubscribe', {
        listkey: listKey,
        emailids: batch.join(','),
      });
    }
  }

  async addContactToListWithData(listId: number | string, contactData: {
    email: string;
    firstName?: string;
    lastName?: string;
    phone?: string;
    company?: string;
    address?: string;
    city?: string;
    state?: string;
    zip?: string;
    country?: string;
    birthday?: string;
  }): Promise<void> {
    const listKey = String(listId);

    // Build contact info JSON for Zoho
    // Zoho's listsubscribe API accepts contactinfo as a JSON string
    const contactInfo: Record<string, string> = {};
    if (contactData.firstName) contactInfo['First Name'] = contactData.firstName;
    if (contactData.lastName) contactInfo['Last Name'] = contactData.lastName;
    if (contactData.phone) contactInfo['Phone'] = contactData.phone;
    if (contactData.company) contactInfo['Company'] = contactData.company;
    if (contactData.address) contactInfo['Street Address'] = contactData.address;
    if (contactData.city) contactInfo['City'] = contactData.city;
    if (contactData.state) contactInfo['State'] = contactData.state;
    if (contactData.zip) contactInfo['Zip Code'] = contactData.zip;
    if (contactData.country) contactInfo['Country'] = contactData.country;
    if (contactData.birthday) contactInfo['Birthday'] = contactData.birthday;

    const params: Record<string, any> = {
      listkey: listKey,
      emailids: contactData.email,
    };

    if (Object.keys(contactInfo).length > 0) {
      params.contactinfo = JSON.stringify(contactInfo);
    }

    await this.makeRequest<any>('POST', '/api/v1.1/listsubscribe', params);
  }

  async removeContactsFromList(listId: number | string, emails: string[]): Promise<void> {
    // Convert to string for Zoho API (listkey is a string)
    const listKey = String(listId);

    // Zoho limits to 10 emails per call for listunsubscribe
    const maxPerCall = 10;

    for (let i = 0; i < emails.length; i += maxPerCall) {
      const batch = emails.slice(i, i + maxPerCall);

      await this.makeRequest<any>('POST', '/api/v1.1/listunsubscribe', {
        listkey: listKey,
        emailids: batch.join(','),
      });
    }
  }

  // ===========================================
  // CONTACTS
  // ===========================================

  async createContact(data: ContactData): Promise<ContactResult> {
    const params: Record<string, any> = {
      email: data.email,
    };

    if (data.attributes) {
      params.contactinfo = JSON.stringify(data.attributes);
    }

    if (data.listIds && data.listIds.length > 0) {
      params.listkey = data.listIds[0]; // Zoho supports single list
    }

    const response = await this.makeRequest<any>('POST', '/api/v1.1/listsubscribe', params);

    return {
      id: response.contactid || '0',
      email: data.email,
      created: true,
    };
  }

  async updateContact(email: string, data: Partial<ContactData>): Promise<ContactResult> {
    // Zoho uses listsubscribe for both create and update
    return this.createContact({ email, ...data, updateEnabled: true });
  }

  async getContact(email: string): Promise<ContactResult | null> {
    // Zoho doesn't have a direct get contact by email API
    // Would need to iterate through lists
    console.warn('[ZohoCampaigns] getContact is not efficiently supported');
    return null;
  }

  async deleteContact(email: string): Promise<void> {
    // Zoho uses listunsubscribe
    console.warn('[ZohoCampaigns] deleteContact requires list context');
  }

  async importContacts(contacts: ContactData[]): Promise<{ taskId: string }> {
    // Zoho supports bulk import via addlistsubscribersinbulk
    // For simplicity, we'll add contacts one by one
    // In production, consider using bulk import API
    for (const contact of contacts) {
      await this.createContact(contact);
    }
    return { taskId: 'manual-import' };
  }

  // ===========================================
  // CAMPAIGNS
  // ===========================================

  async createCampaign(options: SendCampaignOptions): Promise<CampaignResult> {
    console.log('[ZohoCampaigns] Creating campaign:', options.name);

    // Zoho Campaigns API requires:
    // - campaignname*, from_email*, subject*, list_details*
    // Note: topicId may also be required for some organizations

    const params: Record<string, any> = {
      campaignname: options.name || 'Untitled Campaign',
      from_email: options.sender.email,
      subject: options.subject || 'No Subject',
      // list_details is mandatory - must be a JSON string of list keys
      list_details: JSON.stringify(options.recipients?.listIds || []),
    };

    if (options.sender.name) {
      params.from_name = options.sender.name;
    }

    // Zoho requires content_url to be a publicly accessible HTTP/HTTPS URL
    // Data URLs are NOT accepted (INVALID_IMPORT_URL error)
    // For local development, we create a draft campaign without content
    if (options.htmlUrl) {
      // Use provided URL directly (for production)
      params.content_url = options.htmlUrl;
      console.log('[ZohoCampaigns] Using content URL:', options.htmlUrl);
    } else if (options.htmlContent) {
      // For local development, we cannot provide HTML content directly
      // Create a draft campaign without content - user must edit in Zoho UI
      console.warn('[ZohoCampaigns] Warning: HTML content provided but no public URL available.');
      console.warn('[ZohoCampaigns] Campaign will be created as draft without content.');
      console.warn('[ZohoCampaigns] You must edit the campaign in Zoho Campaigns UI to add content.');
      // Don't set content_url - campaign will be a draft
    }

    console.log('[ZohoCampaigns] Create campaign params:', {
      campaignname: params.campaignname,
      from_email: params.from_email,
      subject: params.subject,
      list_details: params.list_details,
      hasContent: !!params.content_url,
    });

    const response = await this.makeRequest<any>('POST', '/api/v1.1/createCampaign', {}, params);

    console.log('[ZohoCampaigns] Create campaign response:', JSON.stringify(response).slice(0, 1000));

    // Zoho returns campaignKey (camelCase) in the response
    const campaignKey = response.campaignKey || response.campaignkey || response.response?.campaignKey || response.response?.campaignkey;

    if (!campaignKey) {
      console.error('[ZohoCampaigns] No campaign key in response:', response);

      // Check for error message
      const errorMessage = response.message || response.error?.message || 'Unknown error';
      throw new Error(`Failed to create campaign: ${errorMessage}. Response: ${JSON.stringify(response)}`);
    }

    console.log('[ZohoCampaigns] Campaign created successfully:', campaignKey);

    return {
      campaignId: campaignKey as unknown as number, // Zoho uses string keys
      status: 'draft',
    };
  }

  async updateCampaign(
    campaignId: number | string,
    options: Partial<SendCampaignOptions>
  ): Promise<CampaignResult> {
    // Zoho doesn't have a direct update campaign API
    // Campaigns are typically cloned and edited
    throw new Error('Direct campaign update is not supported. Use clone and create new.');
  }

  async getCampaign(campaignId: number | string): Promise<{
    id: number;
    name: string;
    subject: string;
    status: string;
    stats?: CampaignStats;
  }> {
    const response = await this.makeRequest<any>('GET', '/api/v1.1/getcampaigndetails', {
      campaignkey: String(campaignId),
    });

    const campaign = response.campaign || response.response?.campaign || response;

    return {
      id: campaign.campaignkey || String(campaignId),
      name: campaign.campaignname || '',
      subject: campaign.subject || '',
      status: this.mapZohoCampaignStatus(campaign.campaignstatus),
      stats: this.parseCampaignStats(campaign),
    };
  }

  async sendCampaign(campaignId: number | string): Promise<void> {
    await this.makeRequest<any>('POST', '/api/v1.1/sendcampaign', {
      campaignkey: String(campaignId),
    });
  }

  async scheduleCampaign(campaignId: number | string, scheduledAt: Date): Promise<void> {
    const date = scheduledAt.toLocaleDateString('en-US', {
      month: '2-digit',
      day: '2-digit',
      year: 'numeric',
    });

    const hour = scheduledAt.getHours();
    const minute = scheduledAt.getMinutes();
    const ampm = hour >= 12 ? 'pm' : 'am';
    const hour12 = hour % 12 || 12;

    await this.makeRequest<any>('POST', '/api/v1.1/sendcampaign', {
      campaignkey: String(campaignId),
      isschedule: true,
      scheduledate: date,
      schedulehour: hour12.toString(),
      scheduleminute: minute.toString().padStart(2, '0'),
      am_pm: ampm,
      sendingTZ: Intl.DateTimeFormat().resolvedOptions().timeZone,
    });
  }

  async sendTestEmail(campaignId: number | string, email: string): Promise<void> {
    // Zoho doesn't have a direct test email API in the same way
    // Tests are typically sent from the UI
    console.warn('[ZohoCampaigns] Test email sending is not directly supported via API');
    throw new Error('Test email sending is not supported via Zoho Campaigns API');
  }

  async deleteCampaign(campaignId: number | string): Promise<void> {
    await this.makeRequest<any>('POST', '/api/v1.1/deletecampaign', {
      campaignkey: String(campaignId),
    });
  }

  // ===========================================
  // CAMPAIGN REPORTS
  // ===========================================

  async getCampaignStats(campaignId: number | string): Promise<CampaignStats> {
    const response = await this.makeRequest<any>('GET', '/api/v1.1/campaignreports', {
      campaignkey: String(campaignId),
    });

    return this.parseCampaignStats(response);
  }

  // ===========================================
  // TEMPLATES
  // ===========================================

  async getTemplates(): Promise<TemplateResult[]> {
    // Zoho Campaigns template API is limited
    // Templates are typically managed through the UI
    console.warn('[ZohoCampaigns] Template management via API is limited');
    return [];
  }

  async createTemplate(data: {
    name: string;
    subject: string;
    htmlContent: string;
    sender: { name: string; email: string };
  }): Promise<{ id: number }> {
    // Zoho Email API v2 has template endpoints
    // For now, return not supported
    throw new Error('Template creation is not supported via Zoho Campaigns API');
  }

  // ===========================================
  // WEBHOOKS
  // ===========================================

  async createWebhook(data: WebhookData): Promise<WebhookResult> {
    const response = await this.client.post('/emailapi/v2/settings/webhook', {
      name: data.description || 'Mengo Webhook',
      type: 'POST',
      url: data.url,
      webhook_actions: data.events,
    });

    return {
      id: response.data.webhook_id,
      url: data.url,
      events: data.events,
    };
  }

  async getWebhooks(): Promise<WebhookResult[]> {
    const response = await this.client.get('/emailapi/v2/settings/webhook');
    const webhooks = response.data.webhooks || [];

    return webhooks.map((w: any) => ({
      id: w.webhook_id,
      url: w.webhook_url,
      events: w.webhook_actions || [],
    }));
  }

  async deleteWebhook(webhookId: number | string): Promise<void> {
    await this.client.delete(`/emailapi/v2/settings/webhook/${webhookId}`);
  }

  // ===========================================
  // HEALTH CHECK
  // ===========================================

  async healthCheck(): Promise<{ status: 'ok' | 'error'; message?: string }> {
    try {
      await this.getLists(1);
      return { status: 'ok' };
    } catch (error: any) {
      return {
        status: 'error',
        message: error.message || 'Unknown error',
      };
    }
  }

  // ===========================================
  // TRANSACTIONAL EMAIL (for automation workflows)
  // ===========================================

  async sendTransactionalEmail(params: {
    to: string;
    subject: string;
    htmlContent?: string;
    htmlUrl?: string;
    templateId?: number;
    sender: { email: string; name: string; id?: number };
    replyTo?: string;
    tags?: string[];
  }): Promise<{ success: boolean; messageId?: string; campaignId?: string | number; error?: string }> {
    try {
      // Zoho Campaigns doesn't have a transactional email API
      // Create a single-recipient campaign and send it
      const lists = await this.getLists(1, 0);
      if (!lists || lists.length === 0) {
        return {
          success: false,
          error: 'No Zoho Campaigns mailing list available. Create a list first.',
        };
      }

      const listKey = String(lists[0].id);

      // Add recipient to the list first
      try {
        await this.addContactsToList(listKey, [params.to]);
      } catch (addErr: any) {
        // Contact may already exist, which is fine
        console.log('[ZohoProvider] Contact may already exist in list:', addErr.message);
      }

      // Build campaign data
      const campaignData: Record<string, string> = {
        campaignname: `[Automation] ${params.subject}`,
        from_email: params.sender.email,
        subject: params.subject,
        list_details: JSON.stringify({ [listKey]: true }),
      };

      // Zoho requires content_url for HTML content (no direct htmlContent support)
      if (params.htmlUrl) {
        campaignData.content_url = params.htmlUrl;
      } else if (params.htmlContent) {
        // For inline HTML, we'd need a temporary content URL
        // Fall back to creating a draft campaign without content
        console.warn('[ZohoProvider] Zoho Campaigns API requires content_url for HTML content. Inline HTML is not supported.');
      }

      const response = await this.makeRequest<{ data?: { campaignkey?: string } }>('POST', '/api/v1.1/createCampaign', campaignData);

      if (response.data && response.data.campaignkey) {
        // Send the campaign immediately
        await this.makeRequest('POST', '/api/v1.1/sendcampaign', {
          campaignkey: response.data.campaignkey,
        });

        return {
          success: true,
          messageId: response.data.campaignkey,
          campaignId: response.data.campaignkey,
        };
      }

      return {
        success: false,
        error: 'Failed to create campaign in Zoho Campaigns',
      };
    } catch (error: any) {
      console.error('[ZohoProvider] Error sending transactional email:', error);
      return {
        success: false,
        error: error.message || 'Failed to send transactional email via Zoho Campaigns',
      };
    }
  }

  // ===========================================
  // HELPER METHODS
  // ===========================================

  private mapZohoCampaignStatus(status: string): string {
    const statusMap: Record<string, string> = {
      '0': 'draft',
      '1': 'scheduled',
      '2': 'sending',
      '3': 'sent',
      '4': 'paused',
      '5': 'cancelled',
      'draft': 'draft',
      'scheduled': 'scheduled',
      'sending': 'sending',
      'sent': 'sent',
      'paused': 'paused',
      'cancelled': 'cancelled',
    };
    return statusMap[status] || 'draft';
  }

  private parseCampaignStats(data: any): CampaignStats {
    return {
      sent: parseInt(data.sent?.toString() || data.total_sent_count || '0', 10),
      delivered: parseInt(data.delivered?.toString() || data.total_delivered_count || '0', 10),
      opened: parseInt(data.opened?.toString() || data.total_opened_count || '0', 10),
      uniqueOpens: parseInt(data.unique_opens?.toString() || data.total_unique_opens || '0', 10),
      clicked: parseInt(data.clicked?.toString() || data.total_click_count || '0', 10),
      uniqueClicks: parseInt(data.unique_clicks?.toString() || data.total_unique_clicks || '0', 10),
      hardBounces: parseInt(data.hard_bounce?.toString() || '0', 10),
      softBounces: parseInt(data.soft_bounce?.toString() || '0', 10),
      unsubscribes: parseInt(data.unsubscribed?.toString() || '0', 10),
      complaints: parseInt(data.spam?.toString() || '0', 10),
    };
  }

  // ===========================================
  // AUTOMATION WORKFLOWS (Not supported by Zoho Campaigns API)
  // ===========================================

  async getAutomations(): Promise<AutomationWorkflow[]> {
    // Zoho Campaigns doesn't have a public automation API
    // Return empty array to maintain interface compatibility
    console.log('[ZohoCampaigns] Automation workflows not supported via API');
    return [];
  }

  async addContactToAutomation(
    workflowId: number,
    email: string,
    attributes?: Record<string, any>,
    listIds?: number[]
  ): Promise<AutomationContactResult> {
    // Zoho Campaigns doesn't have a public automation API
    // Return error to indicate this feature is not available
    return {
      success: false,
      message: 'Automation workflows are not supported by Zoho Campaigns API. Please use Zoho Campaigns dashboard to manage workflows.',
    };
  }

  async removeContactFromAutomation(workflowId: number, email: string): Promise<void> {
    // Zoho Campaigns doesn't have a public automation API
    throw new Error('Automation workflows are not supported by Zoho Campaigns API');
  }

  async getAutomationContacts(
    workflowId: number,
    limit?: number,
    offset?: number
  ): Promise<{ contacts: ContactResult[]; total: number }> {
    // Zoho Campaigns doesn't have a public automation API
    return { contacts: [], total: 0 };
  }
}