/**
 * Gmail Service
 * Handles Gmail API operations
 */

import { google } from 'googleapis'
import { OAuth2Client } from 'google-auth-library'
import { config } from '../config/index.mjs'
import { log } from '../middleware/logger.mjs'

/**
 * Gmail Service Class
 */
export class GmailService {
  constructor(accessToken, refreshToken = null) {
    this.auth = new OAuth2Client(
      config.google.clientId,
      config.google.clientSecret,
      config.google.redirectUri
    )

    this.auth.setCredentials({
      access_token: accessToken,
      refresh_token: refreshToken,
    })

    this.gmail = google.gmail({ version: 'v1', auth: this.auth })
  }

  /**
   * Get user's email address
   */
  async getProfile() {
    const { data } = await this.gmail.users.getProfile({ userId: 'me' })
    return data
  }

  /**
   * List emails from inbox
   * @param {number} maxResults - Maximum number of emails to fetch
   * @param {string} pageToken - Pagination token
   * @param {string} query - Gmail search query
   */
  async listEmails(maxResults = 50, pageToken = null, query = 'in:inbox is:unread') {
    const params = {
      userId: 'me',
      maxResults,
      q: query,
    }

    if (pageToken) {
      params.pageToken = pageToken
    }

    const { data } = await this.gmail.users.messages.list(params)

    return {
      messages: data.messages || [],
      nextPageToken: data.nextPageToken,
      resultSizeEstimate: data.resultSizeEstimate,
    }
  }

  /**
   * Get full email details
   * @param {string} messageId - Message ID
   */
  async getEmail(messageId) {
    const { data } = await this.gmail.users.messages.get({
      userId: 'me',
      id: messageId,
      format: 'full',
    })

    // Parse headers
    const headers = {}
    data.payload?.headers?.forEach(h => {
      headers[h.name.toLowerCase()] = h.value
    })

    return {
      id: data.id,
      threadId: data.threadId,
      snippet: data.snippet,
      labelIds: data.labelIds || [],
      headers,
      internalDate: data.internalDate,
      sizeEstimate: data.sizeEstimate,
    }
  }

  /**
   * Batch get multiple emails
   * @param {string[]} messageIds - Array of message IDs
   */
  async batchGetEmails(messageIds) {
    // Gmail API supports batch requests, but we'll do simple parallel for now
    const emails = await Promise.all(
      messageIds.map(id => this.getEmail(id).catch(e => {
        log.warn(`E-Mail abrufen fehlgeschlagen: ${id}`, { error: e.message })
        return null
      }))
    )

    return emails.filter(Boolean)
  }

  /**
   * Create or get a label
   * @param {string} name - Label name (e.g., "MailFlow/VIP")
   * @param {string} color - Optional label color (must be from Gmail's palette)
   */
  async createLabel(name, color = null) {
    // Gmail's allowed label colors (background colors)
    const GMAIL_COLORS = {
      red: { backgroundColor: '#fb4c2f', textColor: '#ffffff' },
      orange: { backgroundColor: '#ffad47', textColor: '#000000' },
      yellow: { backgroundColor: '#fad165', textColor: '#000000' },
      green: { backgroundColor: '#16a766', textColor: '#ffffff' },
      teal: { backgroundColor: '#43d692', textColor: '#000000' },
      blue: { backgroundColor: '#4a86e8', textColor: '#ffffff' },
      purple: { backgroundColor: '#a479e2', textColor: '#ffffff' },
      pink: { backgroundColor: '#f691b3', textColor: '#000000' },
      gray: { backgroundColor: '#666666', textColor: '#ffffff' },
    }

    // Map our colors to Gmail colors
    const colorMap = {
      '#ff0000': GMAIL_COLORS.red,      // VIP
      '#4285f4': GMAIL_COLORS.blue,     // Kunden
      '#0f9d58': GMAIL_COLORS.green,    // Rechnungen
      '#9c27b0': GMAIL_COLORS.purple,   // Newsletter
      '#ff9800': GMAIL_COLORS.orange,   // Werbung
      '#00bcd4': GMAIL_COLORS.teal,     // Social
      '#f44336': GMAIL_COLORS.red,      // Security
      '#673ab7': GMAIL_COLORS.purple,   // Kalender
      '#607d8b': GMAIL_COLORS.gray,     // Review
    }

    try {
      // Check if label exists
      const { data } = await this.gmail.users.labels.list({ userId: 'me' })
      const existing = data.labels?.find(l => l.name === name)

      if (existing) {
        return existing
      }

      // Create new label
      const labelData = {
        name,
        labelListVisibility: 'labelShow',
        messageListVisibility: 'show',
      }

      // Use mapped Gmail color if available
      if (color && colorMap[color]) {
        labelData.color = colorMap[color]
      } else if (color) {
        // Default to blue if color not in map
        labelData.color = GMAIL_COLORS.blue
      }

      const { data: created } = await this.gmail.users.labels.create({
        userId: 'me',
        requestBody: labelData,
      })

      log.success(`Gmail Label erstellt: ${name}`)
      return created
    } catch (error) {
      log.error(`Label erstellen fehlgeschlagen: ${name}`, { error: error.message })
      return null
    }
  }

  /**
   * Add labels to a message
   * @param {string} messageId - Message ID
   * @param {string[]} labelIds - Label IDs to add
   */
  async addLabels(messageId, labelIds) {
    await this.gmail.users.messages.modify({
      userId: 'me',
      id: messageId,
      requestBody: {
        addLabelIds: labelIds,
      },
    })
  }

  /**
   * Remove labels from a message
   * @param {string} messageId - Message ID
   * @param {string[]} labelIds - Label IDs to remove
   */
  async removeLabels(messageId, labelIds) {
    await this.gmail.users.messages.modify({
      userId: 'me',
      id: messageId,
      requestBody: {
        removeLabelIds: labelIds,
      },
    })
  }

  /**
   * Archive a message (remove from INBOX)
   * @param {string} messageId - Message ID
   */
  async archiveEmail(messageId) {
    await this.removeLabels(messageId, ['INBOX'])
  }

  /**
   * Move message to trash
   * @param {string} messageId - Message ID
   */
  async trashEmail(messageId) {
    await this.gmail.users.messages.trash({
      userId: 'me',
      id: messageId,
    })
  }

  /**
   * Mark message as read
   * @param {string} messageId - Message ID
   */
  async markAsRead(messageId) {
    await this.removeLabels(messageId, ['UNREAD'])
  }

  /**
   * Mark message as unread
   * @param {string} messageId - Message ID
   */
  async markAsUnread(messageId) {
    await this.addLabels(messageId, ['UNREAD'])
  }

  /**
   * Star a message
   * @param {string} messageId - Message ID
   */
  async starEmail(messageId) {
    await this.addLabels(messageId, ['STARRED'])
  }

  /**
   * Get all labels
   */
  async getLabels() {
    const { data } = await this.gmail.users.labels.list({ userId: 'me' })
    return data.labels || []
  }

  /**
   * Delete a label by ID
   */
  async deleteLabel(labelId) {
    try {
      await this.gmail.users.labels.delete({
        userId: 'me',
        id: labelId,
      })
      return true
    } catch (error) {
      log.warn(`Label löschen fehlgeschlagen: ${labelId}`, { error: error.message })
      return false
    }
  }

  /**
   * Cleanup old MailFlow labels
   * Removes all labels starting with "MailFlow/" and old German labels
   */
  async cleanupOldLabels() {
    // Old labels to remove (German and old format)
    const OLD_LABELS = [
      // Old "MailFlow/" prefix labels
      'MailFlow/',
      // Old German labels
      'Wichtig', 'Kunden', 'Rechnungen', 'Sicherheit', 'Termine', 'Prüfen', 'Werbung',
      'VIP / Wichtig', 'Kunden / Projekte', 'Rechnungen / Belege', 
      'Werbung / Promotions', 'Social / Benachrichtigungen', 'Security / 2FA',
      'Kalender / Events', 'Review / Unklar',
    ]

    try {
      const labels = await this.getLabels()
      
      // Filter labels that match old patterns
      const labelsToDelete = labels.filter(l => {
        if (!l.name) return false
        // Check for MailFlow/ prefix
        if (l.name.startsWith('MailFlow/')) return true
        // Check for exact matches with old labels
        if (OLD_LABELS.includes(l.name)) return true
        return false
      })
      
      let deleted = 0
      for (const label of labelsToDelete) {
        if (await this.deleteLabel(label.id)) {
          log.info(`Old label deleted: ${label.name}`)
          deleted++
        }
      }
      
      return deleted
    } catch (error) {
      log.error('Cleanup failed', { error: error.message })
      return 0
    }
  }

  /**
   * Setup Gmail push notifications
   * @param {string} webhookUrl - Webhook URL for notifications
   */
  async setupWatch(webhookUrl) {
    const { data } = await this.gmail.users.watch({
      userId: 'me',
      requestBody: {
        labelIds: ['INBOX'],
        topicName: webhookUrl, // Should be a Cloud Pub/Sub topic
        labelFilterAction: 'include',
      },
    })

    return data
  }

  /**
   * Stop watching for push notifications
   */
  async stopWatch() {
    await this.gmail.users.stop({ userId: 'me' })
  }

  /**
   * Get history changes since a historyId
   * @param {string} startHistoryId - History ID to start from
   */
  async getHistory(startHistoryId) {
    const { data } = await this.gmail.users.history.list({
      userId: 'me',
      startHistoryId,
      historyTypes: ['messageAdded', 'labelAdded', 'labelRemoved'],
    })

    return data.history || []
  }
}

export default GmailService
