import { logger } from '../../utils/logger.js';
import { db } from '../../config/database.js';
import { emails, contacts } from '../../db/schema.js';
import { eq, and } from 'drizzle-orm';
import { jmapRequest, getMailboxes, getIdentities } from './client.js';

/**
 * Mark email as read/unread in JMAP and local DB
 */
export const markEmailAsRead = async (jmapConfig, userId, jmapId, isRead) => {
  try {
    logger.info(`Označujem email ${jmapId} ako ${isRead ? 'prečítaný' : 'neprečítaný'}`);

    // Get current keywords
    const getResponse = await jmapRequest(jmapConfig, [
      [
        'Email/get',
        {
          accountId: jmapConfig.accountId,
          ids: [jmapId],
          properties: ['keywords', 'mailboxIds'],
        },
        'get1',
      ],
    ]);

    const email = getResponse.methodResponses[0][1].list?.[0];

    if (!email) {
      // Update local DB even if JMAP fails
      await db.update(emails).set({ isRead }).where(eq(emails.jmapId, jmapId));
      throw new Error('Email nebol nájdený v JMAP');
    }

    // Build new keywords
    const newKeywords = { ...email.keywords };
    if (isRead) {
      newKeywords['$seen'] = true;
    } else {
      delete newKeywords['$seen'];
    }

    // Update in JMAP
    const updateResponse = await jmapRequest(jmapConfig, [
      [
        'Email/set',
        {
          accountId: jmapConfig.accountId,
          update: {
            [jmapId]: {
              keywords: newKeywords,
            },
          },
        },
        'set1',
      ],
    ]);

    const updateResult = updateResponse.methodResponses[0][1];

    // Check if update succeeded
    if (updateResult.notUpdated?.[jmapId]) {
      logger.error('Nepodarilo sa aktualizovať email v JMAP', updateResult.notUpdated[jmapId]);
    }

    // Update in local DB
    await db.update(emails).set({ isRead }).where(eq(emails.jmapId, jmapId));

    logger.success(`Email ${jmapId} označený ako ${isRead ? 'prečítaný' : 'neprečítaný'}`);
    return { success: true };
  } catch (error) {
    logger.error('Chyba pri označovaní emailu ako prečítaného', error);

    // Still try to update local DB
    try {
      await db.update(emails).set({ isRead }).where(eq(emails.jmapId, jmapId));
    } catch (dbError) {
      logger.error('Nepodarilo sa aktualizovať databázu', dbError);
    }

    throw error;
  }
};

/**
 * Send email via JMAP
 */
export const sendEmail = async (jmapConfig, userId, emailAccountId, to, subject, body, inReplyTo = null, threadId = null) => {
  try {
    logger.info(`Odosielam email na: ${to}`);

    // Get mailboxes
    const mailboxes = await getMailboxes(jmapConfig);
    const sentMailbox = mailboxes.find((m) => m.role === 'sent' || m.name === 'Sent');

    if (!sentMailbox) {
      throw new Error('Priečinok Odoslané nebol nájdený');
    }

    // Create email draft
    const createResponse = await jmapRequest(jmapConfig, [
      [
        'Email/set',
        {
          accountId: jmapConfig.accountId,
          create: {
            draft: {
              mailboxIds: {
                [sentMailbox.id]: true,
              },
              keywords: {
                $draft: true,
              },
              from: [{ email: jmapConfig.username }],
              to: [{ email: to }],
              subject: subject,
              textBody: [{ partId: 'body', type: 'text/plain' }],
              bodyValues: {
                body: {
                  value: body,
                },
              },
              inReplyTo: inReplyTo ? [inReplyTo] : null,
              references: inReplyTo ? [inReplyTo] : null,
            },
          },
        },
        'set1',
      ],
    ]);

    const createdEmailId = createResponse.methodResponses[0][1].created?.draft?.id;

    if (!createdEmailId) {
      throw new Error('Nepodarilo sa vytvoriť koncept emailu');
    }

    // Get user identity
    const identities = await getIdentities(jmapConfig);
    const identity = identities.find((i) => i.email === jmapConfig.username) || identities[0];

    if (!identity) {
      throw new Error('Nenašla sa identita pre odosielanie emailov');
    }

    // Submit the email
    const submitResponse = await jmapRequest(jmapConfig, [
      [
        'EmailSubmission/set',
        {
          accountId: jmapConfig.accountId,
          create: {
            submission: {
              emailId: createdEmailId,
              identityId: identity.id,
            },
          },
        },
        'submit1',
      ],
    ]);

    const submissionId = submitResponse.methodResponses[0][1].created?.submission?.id;

    if (!submissionId) {
      throw new Error('Nepodarilo sa odoslať email');
    }

    logger.success(`Email úspešne odoslaný na ${to}`);

    // Find contact by recipient email address to properly link the sent email
    const [recipientContact] = await db
      .select()
      .from(contacts)
      .where(
        and(
          eq(contacts.emailAccountId, emailAccountId),
          eq(contacts.email, to)
        )
      )
      .limit(1);

    // Save sent email to database
    const messageId = `<${Date.now()}.${Math.random().toString(36).substr(2, 9)}@${jmapConfig.username.split('@')[1]}>`;

    await db.insert(emails).values({
      emailAccountId,
      contactId: recipientContact?.id || null, // Link to contact if recipient is in contacts
      companyId: recipientContact?.companyId || null,
      jmapId: createdEmailId,
      messageId,
      threadId: threadId || messageId,
      inReplyTo: inReplyTo || null,
      from: jmapConfig.username,
      to,
      subject,
      body,
      date: new Date(),
      isRead: true, // Sent emails are always read
      sentByUserId: userId, // Track who sent this email
    });

    logger.info(`Odoslaný email prepojený s kontaktom: ${recipientContact ? recipientContact.id : 'žiadny (nie je v kontaktoch)'}`);

    return { success: true, messageId };
  } catch (error) {
    logger.error('Chyba pri odosielaní emailu', error);
    throw error;
  }
};
