import * as crmEmailService from '../services/crm-email.service.js';
import * as contactService from '../services/contact.service.js';
import * as emailAccountService from '../services/email-account.service.js';
import { markEmailAsRead, sendEmail, getJmapConfig, getJmapConfigFromAccount, syncEmailsFromSender, searchEmailsJMAP as searchEmailsJMAPService } from '../services/jmap/index.js';
import { getUserById } from '../services/auth.service.js';
import { logger } from '../utils/logger.js';

/**
 * Get all emails for authenticated user
 * GET /api/emails?accountId=xxx (REQUIRED)
 */
export const getEmails = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { accountId } = req;

    // Verify user has access to this email account
    await emailAccountService.getEmailAccountById(accountId, userId);

    const emails = await crmEmailService.getEmailsForAccount(accountId);

    res.status(200).json({
      success: true,
      count: emails.length,
      data: emails,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get emails by thread (conversation)
 * GET /api/emails/thread/:threadId?accountId=xxx (accountId required)
 */
export const getThread = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { threadId } = req.params;
    const { accountId } = req;

    // Verify user has access to this email account
    await emailAccountService.getEmailAccountById(accountId, userId);

    const thread = await crmEmailService.getEmailThread(accountId, threadId);

    res.status(200).json({
      success: true,
      count: thread.length,
      data: thread,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Search emails
 * GET /api/emails/search?q=query&accountId=xxx (accountId required)
 */
export const searchEmails = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { q } = req.query;
    const { accountId } = req;

    // Verify user has access to this email account
    await emailAccountService.getEmailAccountById(accountId, userId);

    const results = await crmEmailService.searchEmails(accountId, q);

    res.status(200).json({
      success: true,
      count: results.length,
      data: results,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get unread count
 * GET /api/emails/unread-count
 * Returns total unread count and per-account counts
 */
export const getUnreadCount = async (req, res, next) => {
  try {
    const userId = req.userId;

    // Get all user's email accounts
    const userAccounts = await emailAccountService.getUserEmailAccounts(userId);
    const emailAccountIds = userAccounts.map((account) => account.id);

    // Get unread count summary for all accounts
    const unreadData = await crmEmailService.getUnreadCountSummary(emailAccountIds);

    res.status(200).json({
      success: true,
      data: {
        count: unreadData.totalUnread,
        totalUnread: unreadData.totalUnread,
        accounts: unreadData.byAccount,
        lastUpdatedAt: new Date().toISOString(),
      },
    });
  } catch (error) {
    logger.error('Chyba v getUnreadCount', { error: error.message });
    next(error);
  }
};

/**
 * Sync latest emails for all contacts from JMAP
 * POST /api/emails/sync
 * Body: { accountId } (optional - defaults to primary account)
 */
export const syncEmails = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { accountId } = req.body;

    // Get email account (or primary if not specified)
    let emailAccount;
    if (accountId) {
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    } else {
      const primaryAccount = await emailAccountService.getPrimaryEmailAccount(userId);
      if (!primaryAccount) {
        return res.status(400).json({
          success: false,
          error: {
            message: 'Najprv musíš pripojiť email účet v Profile',
            statusCode: 400,
          },
        });
      }
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(primaryAccount.id, userId);
    }

    // Get contacts for this email account
    const contacts = await contactService.getContactsForEmailAccount(emailAccount.id);

    if (!contacts.length) {
      return res.status(200).json({
        success: true,
        message: 'Žiadne kontakty na synchronizáciu',
        data: { contacts: 0, synced: 0, newEmails: 0 },
      });
    }

    const jmapConfig = getJmapConfigFromAccount(emailAccount);
    let totalSynced = 0;
    let totalNew = 0;

    for (const contact of contacts) {
      try {
        const { total, saved } = await syncEmailsFromSender(
          jmapConfig,
          emailAccount.id,
          contact.id,
          contact.email,
          { limit: 50 }
        );
        totalSynced += total;
        totalNew += saved;
      } catch (syncError) {
        logger.error('Nepodarilo sa synchronizovať emaily pre kontakt', { contactEmail: contact.email, error: syncError.message });
      }
    }

    res.status(200).json({
      success: true,
      message: 'Emaily synchronizované',
      data: {
        contacts: contacts.length,
        synced: totalSynced,
        newEmails: totalNew,
      },
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Mark email as read/unread
 * PATCH /api/emails/:jmapId/read?accountId=xxx
 */
export const markAsRead = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { jmapId } = req.params;
    const { isRead } = req.body;
    const accountId = req.accountId || req.body.accountId;

    if (!accountId) {
      return res.status(400).json({
        success: false,
        error: {
          message: 'accountId je povinný parameter',
          statusCode: 400,
        },
      });
    }

    // Verify user has access to this email account
    const emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    const jmapConfig = getJmapConfigFromAccount(emailAccount);

    await markEmailAsRead(jmapConfig, userId, jmapId, isRead);

    res.status(200).json({
      success: true,
      message: `Email označený ako ${isRead ? 'prečítaný' : 'neprečítaný'}`,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Mark all emails from contact as read
 * POST /api/emails/contact/:contactId/read?accountId=xxx
 */
export const markContactEmailsRead = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { contactId } = req.params;
    const { accountId } = req;

    // Verify user has access to this email account
    const emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    const jmapConfig = getJmapConfigFromAccount(emailAccount);

    // Mark emails as read in database
    const count = await crmEmailService.markContactEmailsAsRead(contactId, accountId);

    // Get the emails that were marked as read to sync with JMAP
    const contactEmails = await crmEmailService.getContactEmailsWithUnread(accountId, contactId);

    // Also mark emails as read on JMAP server
    if (contactEmails && contactEmails.length > 0) {
      logger.info(`Marking ${contactEmails.length} emails as read on JMAP server`);

      for (const email of contactEmails) {
        if (!email.jmapId || email.isRead) {
          continue;
        }
        try {
          await markEmailAsRead(jmapConfig, userId, email.jmapId, true);
        } catch (jmapError) {
          logger.error('Nepodarilo sa označiť JMAP email ako prečítaný', { jmapId: email.jmapId, error: jmapError.message });
        }
      }
    }

    res.status(200).json({
      success: true,
      message: `Označených ${count} emailov ako prečítaných`,
      data: { count },
    });
  } catch (error) {
    logger.error('Chyba v markContactEmailsRead', { error: error.message });
    next(error);
  }
};

/**
 * Mark entire thread as read
 * POST /api/emails/thread/:threadId/read?accountId=xxx
 */
export const markThreadRead = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { threadId } = req.params;
    const { accountId } = req;

    // Verify user has access to this email account
    const emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    const jmapConfig = getJmapConfigFromAccount(emailAccount);

    const threadEmails = await crmEmailService.getEmailThread(accountId, threadId);
    const unreadEmails = threadEmails.filter((email) => !email.isRead);

    // Mark emails as read on JMAP server
    for (const email of unreadEmails) {
      if (!email.jmapId) {
        continue;
      }
      try {
        await markEmailAsRead(jmapConfig, userId, email.jmapId, true);
      } catch (jmapError) {
        logger.error('Nepodarilo sa označiť JMAP email ako prečítaný', { jmapId: email.jmapId, error: jmapError.message });
      }
    }

    // Mark thread as read in database
    const count = await crmEmailService.markThreadAsRead(accountId, threadId);

    res.status(200).json({
      success: true,
      message: 'Konverzácia označená ako prečítaná',
      count,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Send email reply
 * POST /api/emails/reply
 * Body: { to, subject, body, inReplyTo, threadId, accountId }
 */
export const replyToEmail = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { to, subject, body, inReplyTo = null, threadId = null, accountId } = req.body;

    if (!to || !subject || !body) {
      return res.status(400).json({
        success: false,
        error: {
          message: 'Chýbajúce povinné polia: to, subject, body',
          statusCode: 400,
        },
      });
    }

    // Get email account (or primary if not specified)
    let emailAccount;
    if (accountId) {
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    } else {
      const primaryAccount = await emailAccountService.getPrimaryEmailAccount(userId);
      if (!primaryAccount) {
        return res.status(400).json({
          success: false,
          error: {
            message: 'Najprv musíš pripojiť email účet v Profile',
            statusCode: 400,
          },
        });
      }
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(primaryAccount.id, userId);
    }

    const jmapConfig = getJmapConfigFromAccount(emailAccount);

    const result = await sendEmail(jmapConfig, userId, emailAccount.id, to, subject, body, inReplyTo, threadId);

    res.status(200).json({
      success: true,
      message: 'Email odoslaný',
      data: result,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Get emails for a specific contact
 * GET /api/emails/contact/:contactId?accountId=xxx
 */
export const getContactEmails = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { contactId } = req.params;
    const accountId = req.accountId || req.query.accountId;

    if (!accountId) {
      return res.status(400).json({
        success: false,
        error: {
          message: 'accountId je povinný parameter',
          statusCode: 400,
        },
      });
    }

    // Verify user has access to this email account
    await emailAccountService.getEmailAccountById(accountId, userId);

    const emails = await crmEmailService.getContactEmailsWithUnread(accountId, contactId);

    res.status(200).json({
      success: true,
      count: emails.length,
      data: emails,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * Search emails using JMAP full-text search
 * GET /api/emails/search-jmap?query=text&limit=50&offset=0&accountId=xxx
 * Searches in: from, to, subject, and email body
 */
export const searchEmailsJMAP = async (req, res, next) => {
  try {
    const userId = req.userId;
    const { query = '', limit = 50, offset = 0, accountId } = req.query;

    logger.debug('searchEmailsJMAP called', { userId, query, limit, offset, accountId });

    // Get email account (or primary if not specified)
    let emailAccount;
    if (accountId) {
      logger.debug('Using provided accountId', { accountId });
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
    } else {
      logger.debug('No accountId provided, using primary account');
      const primaryAccount = await emailAccountService.getPrimaryEmailAccount(userId);
      if (!primaryAccount) {
        return res.status(400).json({
          success: false,
          error: {
            message: 'Najprv musíš pripojiť email účet v Profile',
            statusCode: 400,
          },
        });
      }
      emailAccount = await emailAccountService.getEmailAccountWithCredentials(primaryAccount.id, userId);
      logger.debug('Using primary account', { accountId: primaryAccount.id });
    }

    const jmapConfig = getJmapConfigFromAccount(emailAccount);

    const results = await searchEmailsJMAPService(
      jmapConfig,
      emailAccount.id,
      query,
      parseInt(limit),
      parseInt(offset)
    );

    res.status(200).json({
      success: true,
      count: results.length,
      data: results,
    });
  } catch (error) {
    logger.error('Chyba v searchEmailsJMAP', { error: error.message });
    next(error);
  }
};
